@iloveagents/foundry-web-ui 0.29.1 → 0.31.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.
Files changed (48) hide show
  1. package/dist/components/ag-ui-runtime-provider.d.ts +8 -3
  2. package/dist/components/ag-ui-runtime-provider.js +76 -33
  3. package/dist/components/assistant-chat.d.ts +1 -15
  4. package/dist/components/assistant-chat.js +4 -5
  5. package/dist/components/chat-bubble.js +3 -4
  6. package/dist/components/chat-context-items.d.ts +6 -0
  7. package/dist/components/chat-context-items.js +25 -0
  8. package/dist/components/chat-context.js +10 -2
  9. package/dist/components/chat-empty-state.js +1 -1
  10. package/dist/components/chat-header.js +2 -1
  11. package/dist/components/composer-add-menu.d.ts +0 -19
  12. package/dist/components/composer-add-menu.js +2 -10
  13. package/dist/components/context-badges.d.ts +0 -14
  14. package/dist/components/context-badges.js +2 -29
  15. package/dist/components/context-bar.d.ts +1 -21
  16. package/dist/components/context-bar.js +3 -74
  17. package/dist/components/focus-chat-pane.js +1 -1
  18. package/dist/components/markdown-text.js +6 -4
  19. package/dist/components/sidebar.js +51 -17
  20. package/dist/components/tool-panel.js +1 -1
  21. package/dist/index.d.ts +6 -5
  22. package/dist/index.js +5 -4
  23. package/dist/lib/ag-ui-adapter.d.ts +3 -0
  24. package/dist/lib/ag-ui-adapter.js +75 -11
  25. package/dist/lib/auth-provider.js +1 -1
  26. package/dist/lib/chat-runs-store.d.ts +40 -0
  27. package/dist/lib/chat-runs-store.js +173 -0
  28. package/dist/lib/merge-chat-state.d.ts +3 -0
  29. package/dist/lib/merge-chat-state.js +21 -0
  30. package/dist/lib/nav-config.js +47 -20
  31. package/dist/lib/theme-runtime.d.ts +23 -0
  32. package/dist/lib/theme-runtime.js +210 -30
  33. package/dist/lib/theme-store.d.ts +3 -1
  34. package/dist/lib/theme-store.js +3 -2
  35. package/dist/lib/use-new-conversation.js +4 -8
  36. package/dist/styles.css +14 -0
  37. package/dist/workbench/chat-header.js +4 -3
  38. package/dist/workbench/conversation-history.d.ts +1 -1
  39. package/dist/workbench/conversation-history.js +75 -19
  40. package/dist/workbench/running-chats-menu.d.ts +3 -0
  41. package/dist/workbench/running-chats-menu.js +20 -0
  42. package/dist/workbench/selection-bridge.js +2 -5
  43. package/dist/workbench/use-workbench-state.d.ts +1 -2
  44. package/dist/workbench/use-workbench-state.js +15 -18
  45. package/dist/workbench/welcome-intro.js +1 -1
  46. package/dist/workbench/workbench-styles.js +54 -6
  47. package/dist/workbench/workbench.js +1 -1
  48. package/package.json +3 -3
@@ -7,7 +7,9 @@
7
7
  export type ThemeMode = "light" | "dark" | "system";
8
8
  interface ThemeState {
9
9
  mode: ThemeMode;
10
- setMode: (mode: ThemeMode) => void;
10
+ setMode: (mode: ThemeMode, options?: {
11
+ persist?: boolean;
12
+ }) => void;
11
13
  /** Cycle through light -> dark -> system. */
12
14
  cycle: () => void;
13
15
  }
@@ -38,8 +38,9 @@ export const useThemeStore = create((set, get) => {
38
38
  }
39
39
  return {
40
40
  mode: initial,
41
- setMode: (mode) => {
42
- localStorage.setItem(STORAGE_KEY, mode);
41
+ setMode: (mode, options) => {
42
+ if (options?.persist !== false)
43
+ localStorage.setItem(STORAGE_KEY, mode);
43
44
  applyTheme(mode);
44
45
  set({ mode });
45
46
  },
@@ -1,7 +1,5 @@
1
1
  import { useCallback } from "react";
2
2
  import { useNavigate } from "react-router";
3
- import { useAui } from "@assistant-ui/react";
4
- import { useStore } from "zustand";
5
3
  import { citationStore } from "@iloveagents/foundry-agent";
6
4
  import { useAGUIAdapter } from "../components/ag-ui-runtime-provider.js";
7
5
  import { useToolPanelStore } from "./tool-panel-store.js";
@@ -13,13 +11,11 @@ import { useChatLifecycleStore } from "./chat-lifecycle-store.js";
13
11
  * Used by ChatHeader and Sidebar to keep behavior in sync.
14
12
  */
15
13
  export function useNewConversation(options) {
16
- const aui = useAui();
17
14
  const { resetThread } = useAGUIAdapter();
18
15
  const navigate = useNavigate();
19
16
  const closePanel = useToolPanelStore((s) => s.closePanel);
20
17
  const resetApp = useAppStore((s) => s.resetAll);
21
18
  const closeMobile = useSidebarStore((s) => s.closeMobile);
22
- const clearCitations = useStore(citationStore, (s) => s.clear);
23
19
  return useCallback(() => {
24
20
  const preserved = options?.preserveNavigation
25
21
  ? {
@@ -28,12 +24,15 @@ export function useNewConversation(options) {
28
24
  }
29
25
  : null;
30
26
  closePanel();
27
+ const sentContext = useAppStore.getState().sentContext;
31
28
  resetApp();
29
+ useAppStore.setState({ sentContext });
32
30
  if (preserved) {
33
31
  useAppStore.setState(preserved);
34
32
  }
35
33
  closeMobile();
36
- clearCitations();
34
+ // Clear only the foreground projection; retained transcripts keep their sources.
35
+ citationStore.setState({ threadId: null, results: [] });
37
36
  // Notify the host app that a new thread is starting. Spaces wires
38
37
  // this to clear its active-chat sticky id so the AGUIRuntimeProvider's
39
38
  // ``effectiveThreadId`` advances to a freshly-minted UUID instead of
@@ -44,7 +43,6 @@ export function useNewConversation(options) {
44
43
  // where there is no ``/`` navigation to clear sticky for us.
45
44
  useChatLifecycleStore.getState().startNewConversation();
46
45
  resetThread();
47
- aui.threads().switchToNewThread();
48
46
  if (options?.navigateToChat ?? true) {
49
47
  navigate("/");
50
48
  }
@@ -53,9 +51,7 @@ export function useNewConversation(options) {
53
51
  resetApp,
54
52
  options?.preserveNavigation,
55
53
  closeMobile,
56
- clearCitations,
57
54
  resetThread,
58
- aui,
59
55
  options?.navigateToChat,
60
56
  navigate,
61
57
  ]);
package/dist/styles.css CHANGED
@@ -1,4 +1,11 @@
1
1
  @theme inline {
2
+ --color-heading: var(--heading, var(--foreground));
3
+ --color-content-heading-1: var(--content-heading-1, var(--heading, var(--foreground)));
4
+ --color-content-heading-2: var(--content-heading-2, var(--heading, var(--foreground)));
5
+ --color-content-heading-3: var(--content-heading-3, var(--foreground));
6
+ --color-content-heading-4: var(--content-heading-4, var(--foreground));
7
+ --color-content-heading-5: var(--content-heading-5, var(--foreground));
8
+ --color-content-heading-6: var(--content-heading-6, var(--foreground));
2
9
  --radius-xs: calc(var(--radius) - 6px);
3
10
  --radius-sm: calc(var(--radius) - 4px);
4
11
  --radius-md: calc(var(--radius) - 2px);
@@ -255,3 +262,10 @@ tr[data-state="selected"] > [data-pinned="cell"] {
255
262
  tr[data-active] > [data-pinned="cell"] {
256
263
  background-color: color-mix(in srgb, var(--primary) 8%, var(--pinned-surface));
257
264
  }
265
+
266
+ @layer base {
267
+ :where(h1, h2, h3, h4, h5, h6) {
268
+ color: var(--heading, var(--foreground));
269
+ font-family: var(--font-heading, inherit);
270
+ }
271
+ }
@@ -1,12 +1,13 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { TooltipIconButton } from "../index.js";
3
- import { SquarePen, PanelLeft, MessageSquare, Menu, History, LoaderCircle } from "lucide-react";
3
+ import { SquarePen, PanelLeft, MessageSquare, Menu, MessagesSquare, LoaderCircle, } from "lucide-react";
4
+ import { RunningChatsMenu } from "./running-chats-menu.js";
4
5
  export function WorkbenchChatHeader({ collapsed, running, chatWidth, buttonClass, toggleNavigation, setCollapsed, showHistory, startChat, returnToChat, openHistory, chatOnly, setContentCollapsed, }) {
5
- return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-chat-header": true, className: `relative flex shrink-0 items-center ${collapsed ? "justify-center" : "gap-1 px-2"}`, children: [!collapsed && !chatWidth.compact && (_jsx(TooltipIconButton, { tooltip: "Open navigation", className: `${buttonClass} preview-mobile-navigation`, "aria-label": "Open navigation", onClick: toggleNavigation, children: _jsx(Menu, { size: 18 }) })), collapsed ? (_jsx(TooltipIconButton, { tooltip: running ? "AI is working — expand chat" : "Expand chat", className: buttonClass, "aria-label": running ? "AI is working — expand chat" : "Expand chat", onClick: () => setCollapsed(false), children: running ? (_jsx(LoaderCircle, { size: 18, className: "animate-spin motion-reduce:animate-none text-primary" })) : (_jsx(MessageSquare, { size: 18 })) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "min-w-0 flex-1 px-2 py-2", children: _jsx("div", { className: "text-sm font-semibold", children: showHistory ? "Conversations" : "Chat" }) }), _jsx(TooltipIconButton, { tooltip: "New chat", className: buttonClass, "aria-label": "New chat", onClick: startChat, children: _jsx(SquarePen, { size: 18 }) }), _jsx(TooltipIconButton, { tooltip: "Chat history", className: buttonClass, "aria-label": "Chat history", "aria-expanded": showHistory, onClick: () => (showHistory ? returnToChat() : openHistory()), children: _jsx(History, { size: 18 }) }), _jsx(TooltipIconButton, { tooltip: "Collapse chat", style: chatOnly || chatWidth.compact ? { display: "none" } : undefined, className: buttonClass, "aria-label": "Collapse chat", onClick: () => {
6
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-chat-header": true, className: `relative flex shrink-0 items-center ${collapsed ? "justify-center" : "gap-1 px-2"}`, children: [!collapsed && !chatWidth.compact && (_jsx(TooltipIconButton, { tooltip: "Open navigation", className: `${buttonClass} preview-mobile-navigation`, "aria-label": "Open navigation", onClick: toggleNavigation, children: _jsx(Menu, { size: 18 }) })), collapsed ? (_jsx(TooltipIconButton, { tooltip: running ? "AI is working — expand chat" : "Expand chat", className: buttonClass, "aria-label": running ? "AI is working — expand chat" : "Expand chat", onClick: () => setCollapsed(false), children: running ? (_jsx(LoaderCircle, { size: 18, className: "animate-spin motion-reduce:animate-none text-primary" })) : (_jsx(MessageSquare, { size: 18 })) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "min-w-0 flex-1 px-2 py-2", children: _jsx("div", { className: "text-sm font-semibold", children: showHistory ? "Conversations" : "Chat" }) }), _jsx(RunningChatsMenu, { onOpen: returnToChat }), _jsx(TooltipIconButton, { tooltip: "New chat", className: buttonClass, "aria-label": "New chat", onClick: startChat, children: _jsx(SquarePen, { size: 18 }) }), _jsx(TooltipIconButton, { tooltip: "Chat history", className: buttonClass, "aria-label": "Chat history", "aria-expanded": showHistory, onClick: () => (showHistory ? returnToChat() : openHistory()), children: _jsx(MessagesSquare, { size: 18 }) }), _jsx(TooltipIconButton, { tooltip: "Collapse chat", style: chatOnly || chatWidth.compact ? { display: "none" } : undefined, className: buttonClass, "aria-label": "Collapse chat", onClick: () => {
6
7
  setContentCollapsed(false);
7
8
  setCollapsed(true);
8
9
  }, children: _jsx(PanelLeft, { size: 18 }) })] }))] }), collapsed && (_jsxs("div", { "data-chat-rail": true, className: "flex flex-col items-center gap-1", children: [_jsx(TooltipIconButton, { tooltip: "Open navigation", className: `${buttonClass} preview-mobile-navigation`, "aria-label": "Open navigation", onClick: toggleNavigation, children: _jsx(Menu, { size: 18 }) }), _jsx(TooltipIconButton, { tooltip: "Chat history", className: buttonClass, "aria-label": "Chat history", onClick: () => {
9
10
  setCollapsed(false);
10
11
  openHistory();
11
- }, children: _jsx(History, { size: 18 }) })] }))] }));
12
+ }, children: _jsx(MessagesSquare, { size: 18 }) })] }))] }));
12
13
  }
@@ -1,4 +1,4 @@
1
- import type { NavGroup } from "../index.js";
1
+ import type { NavGroup } from "../lib/nav-config.js";
2
2
  /** History is a view of existing navigation targets, never a second chat runtime. */
3
3
  export declare function ConversationHistory({ groups, workspaceId, onClose, showBack, welcome, compact, onViewAll, entityId, rootContext, }: {
4
4
  groups: NavGroup[];
@@ -1,12 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, } from "../index.js";
2
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, } from "../ui/dropdown-menu.js";
3
3
  import { Button, Input } from "@iloveagents/foundry-web-primitives";
4
4
  import { Fragment, useEffect, useState } from "react";
5
5
  import { Link } from "react-router";
6
- import { ArrowLeft, MessageSquare, MoreHorizontal, Pin, Loader2, ChevronDown, Check, History, } from "lucide-react";
6
+ import { ArrowLeft, MessageSquare, MoreHorizontal, Pin, Loader2, ChevronDown, Check, MessagesSquare, PauseCircle, Copy, } from "lucide-react";
7
+ import { useChatRuns, isChatRunActive } from "../lib/chat-runs-store.js";
7
8
  /** History is a view of existing navigation targets, never a second chat runtime. */
8
9
  export function ConversationHistory({ groups, workspaceId, onClose, showBack = true, welcome = false, compact = false, onViewAll, entityId, rootContext = false, }) {
9
10
  const [loadingTo, setLoadingTo] = useState(null);
11
+ const [copiedId, setCopiedId] = useState(null);
10
12
  const [loadError, setLoadError] = useState(null);
11
13
  const [all, setAll] = useState(!workspaceId);
12
14
  useEffect(() => setAll(!workspaceId), [workspaceId]);
@@ -16,28 +18,68 @@ export function ConversationHistory({ groups, workspaceId, onClose, showBack = t
16
18
  groups
17
19
  .filter((g) => g.meta?.type === "recent-chats" || g.meta?.type === "pinned-chats")
18
20
  .flatMap((g) => g.items);
21
+ const runs = useChatRuns((s) => s.runs);
22
+ const runFor = (item) => Object.values(runs).find((run) => (run.conversationUrl ?? `/chat/${encodeURIComponent(run.threadId)}`) === item.to);
19
23
  const workspaceItems = all || !workspaceId
20
24
  ? allItems
21
25
  : (scoped?.meta?.workspaceConversations ?? scoped?.items ?? []);
22
- const scopedItems = compact && workspaceId && !rootContext
23
- ? workspaceItems.filter((item) => Boolean(entityId) && item.meta?.previewEntityId === entityId)
24
- : workspaceItems;
25
- const items = [...new Map(scopedItems.map((item) => [item.to, item])).values()]
26
- .filter((item) => item.meta?.type !== "show-all-chats")
26
+ // In-memory runs appear immediately, before the server refreshes its nav rows.
27
+ // A persisted title/actions win, while the live run owns its current location.
28
+ const merged = new Map(workspaceItems.map((item) => [item.to, item]));
29
+ for (const run of Object.values(runs)) {
30
+ const to = run.conversationUrl ?? `/chat/${encodeURIComponent(run.threadId)}`;
31
+ const saved = allItems.find((item) => item.to === to);
32
+ if (saved && !isChatRunActive(run))
33
+ continue;
34
+ if (!all && workspaceId && !merged.has(to) && run.contextMeta?.spacesRootId !== workspaceId) {
35
+ merged.delete(to);
36
+ continue;
37
+ }
38
+ merged.set(to, {
39
+ ...saved,
40
+ to,
41
+ label: saved?.label ?? run.title,
42
+ icon: MessageSquare,
43
+ meta: {
44
+ ...saved?.meta,
45
+ previewEntityId: run.contextMeta?.spacesEntityId ?? saved?.meta?.previewEntityId,
46
+ previewEntityName: run.pageLabel ?? saved?.meta?.previewEntityName,
47
+ },
48
+ });
49
+ }
50
+ const items = [...merged.values()]
51
+ .filter((item) => !(compact && workspaceId && !rootContext) ||
52
+ (Boolean(entityId) && item.meta?.previewEntityId === entityId))
53
+ .filter((item) => !["show-all-chats", "no-chats-placeholder"].includes(String(item.meta?.type)))
27
54
  .filter((item) => item.label.toLocaleLowerCase().includes(search.toLocaleLowerCase()))
28
- .sort((a, b) => Number(Boolean(b.meta?.pinned)) - Number(Boolean(a.meta?.pinned)));
55
+ .sort((a, b) => {
56
+ const active = (item) => {
57
+ const run = runFor(item);
58
+ return run && isChatRunActive(run) ? 1 : 0;
59
+ };
60
+ return (active(b) - active(a) || Number(Boolean(b.meta?.pinned)) - Number(Boolean(a.meta?.pinned)));
61
+ });
29
62
  const visibleItems = compact ? items.slice(0, 3) : items;
30
- const pinnedItems = visibleItems.filter((item) => item.meta?.pinned);
31
- const sections = pinnedItems.length
32
- ? [
63
+ const activeItems = visibleItems.filter((item) => {
64
+ const run = runFor(item);
65
+ return run && isChatRunActive(run);
66
+ });
67
+ const idleItems = visibleItems.filter((item) => !activeItems.includes(item));
68
+ const pinnedItems = idleItems.filter((item) => item.meta?.pinned);
69
+ const sections = compact
70
+ ? [{ label: "", items: visibleItems }]
71
+ : [
72
+ { label: "Running", items: activeItems },
33
73
  { label: "Pinned", items: pinnedItems },
34
- { label: "Recent chats", items: visibleItems.filter((item) => !item.meta?.pinned) },
35
- ]
36
- : [{ label: "", items: visibleItems }];
74
+ {
75
+ label: activeItems.length || pinnedItems.length ? "Recent chats" : "",
76
+ items: idleItems.filter((item) => !item.meta?.pinned),
77
+ },
78
+ ];
37
79
  return (_jsxs("section", { "data-conversation-history": true, "aria-label": compact ? "Recent conversations" : "Chat history", className: compact ? "w-full" : "mx-auto flex min-h-0 w-full max-w-3xl flex-1 flex-col px-4 pb-4", children: [welcome && (_jsxs("div", { className: "pb-6 pt-8", children: [_jsx("h1", { className: "text-xl font-semibold", children: "How can I help?" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Start something new or continue a recent chat." })] })), showBack && (_jsxs("button", { onClick: onClose, className: "mb-4 flex items-center gap-2 py-2 text-xs text-muted-foreground hover:text-foreground", children: [_jsx(ArrowLeft, { size: 14 }), " Back to chat"] })), (!compact || items.length > 0) && (_jsx("div", { className: "mb-2 mt-2 flex items-center justify-between", children: _jsx("h2", { className: compact ? "text-xs font-medium text-muted-foreground" : "text-base font-semibold", children: compact ? "Recent conversations" : "Conversation history" }) })), Boolean(workspaceId) && !compact && (_jsx("div", { className: "mb-3", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", "aria-label": "History filter", className: "w-full justify-between font-normal shadow-none", children: [_jsx("span", { className: "truncate", children: all ? "All conversations" : "Last used in this workspace" }), _jsx(ChevronDown, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": "true" })] }) }), _jsx(DropdownMenuContent, { align: "start", className: "w-[var(--radix-dropdown-menu-trigger-width)]", children: [
38
80
  { value: false, label: "Last used in this workspace" },
39
81
  { value: true, label: "All conversations" },
40
- ].map((option) => (_jsxs(DropdownMenuItem, { role: "menuitemradio", "aria-checked": all === option.value, onSelect: () => setAll(option.value), children: [_jsx("span", { className: "flex-1", children: option.label }), all === option.value && _jsx(Check, { className: "size-4", "aria-hidden": "true" })] }, option.label))) })] }) })), !compact && (_jsx(Input, { "aria-label": "Search chats", placeholder: "Search chats", value: search, onChange: (event) => setSearch(event.target.value), className: "mb-3" })), loadError && (_jsx("p", { role: "alert", className: "mb-2 text-xs text-destructive", children: loadError })), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto", "aria-busy": Boolean(loadingTo), children: [sections
82
+ ].map((option) => (_jsxs(DropdownMenuItem, { role: "menuitemradio", "aria-checked": all === option.value, onSelect: () => setAll(option.value), children: [_jsx("span", { className: "flex-1", children: option.label }), all === option.value && _jsx(Check, { className: "size-4", "aria-hidden": "true" })] }, option.label))) })] }) })), !compact && (_jsx(Input, { "aria-label": "Search chats", placeholder: "Search chats", value: search, onChange: (event) => setSearch(event.target.value), className: "mb-3" })), _jsx("span", { className: "sr-only", role: "status", children: copiedId ? "Chat ID copied" : "" }), loadError && (_jsx("p", { role: "alert", className: "mb-2 text-xs text-destructive", children: loadError })), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto", "aria-busy": Boolean(loadingTo), children: [sections
41
83
  .filter((section) => section.items.length)
42
84
  .map((section) => (_jsxs("section", { "aria-label": section.label || "Recent chats", className: "mb-4 last:mb-0", children: [section.label && (_jsx("h3", { "data-conversation-section-label": true, className: "px-2 py-2 text-xs font-medium text-muted-foreground", children: section.label })), section.items.map((item) => item.disabled ? (_jsx("p", { className: "py-3 text-sm text-muted-foreground", children: item.label }, item.to)) : (_jsxs("div", { className: "group flex items-center rounded-lg hover:bg-muted", children: [_jsxs(Link, { to: item.to, onClick: (event) => {
43
85
  if (loadingTo) {
@@ -69,7 +111,7 @@ export function ConversationHistory({ groups, workspaceId, onClose, showBack = t
69
111
  }
70
112
  setLoadingTo(null);
71
113
  onClose();
72
- }, "data-conversation-row": true, className: "flex min-w-0 flex-1 items-center gap-2 rounded-lg px-2 py-1.5 text-sm hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary", children: [loadingTo === item.to ? (_jsx(Loader2, { className: "size-4 shrink-0 animate-spin text-muted-foreground", "aria-label": "Opening chat" })) : item.meta?.pinned ? (_jsx(Pin, { className: "size-4 shrink-0 text-muted-foreground", "aria-label": "Pinned chat" })) : (_jsx(MessageSquare, { className: "size-4 shrink-0 text-muted-foreground" })), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate", children: item.label }), " ", (!compact || rootContext) && (_jsx("span", { className: "block truncate text-xs text-muted-foreground", children: !all &&
114
+ }, "data-conversation-row": true, className: "flex min-w-0 flex-1 items-center gap-2 rounded-lg px-2 py-1.5 text-sm hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary", children: [loadingTo === item.to ? (_jsx(Loader2, { className: "size-4 shrink-0 animate-spin text-muted-foreground", "aria-label": "Opening chat" })) : runFor(item)?.status === "running" ? (_jsx(Loader2, { className: "size-4 shrink-0 animate-spin text-primary motion-reduce:animate-none", "aria-hidden": true })) : runFor(item)?.status === "waiting" ? (_jsx(PauseCircle, { className: "size-4 shrink-0 text-primary", "aria-hidden": true })) : item.meta?.pinned ? (_jsx(Pin, { className: "size-4 shrink-0 text-muted-foreground", "aria-label": "Pinned chat" })) : (_jsx(MessageSquare, { className: "size-4 shrink-0 text-muted-foreground" })), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate", children: item.label }), " ", runFor(item) && isChatRunActive(runFor(item)) ? (_jsx("span", { className: "block text-xs text-primary", children: runFor(item)?.status === "waiting" ? "Waiting for you" : "Running" })) : ((!compact || rootContext) && (_jsx("span", { className: "block truncate text-xs text-muted-foreground", children: !all &&
73
115
  typeof item.meta?.previewEntityName === "string" &&
74
116
  item.meta.previewEntityName
75
117
  ? `Last at ${item.meta.previewEntityName}`
@@ -80,7 +122,21 @@ export function ConversationHistory({ groups, workspaceId, onClose, showBack = t
80
122
  ? `Last in ${item.meta.previewSpaceName}`
81
123
  : item.meta?.previewContextUnavailable
82
124
  ? "Location unavailable"
83
- : "Last outside a workspace" }))] })] }), Boolean(item.actions?.length) && (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Actions for ${item.label}`, className: "mr-1 inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100 [@media(hover:none)]:opacity-100 hover:bg-background", children: _jsx(MoreHorizontal, { className: "size-4" }) }) }), _jsx(DropdownMenuContent, { align: "end", children: item.actions?.map((action) => (_jsxs(Fragment, { children: [action.separator && _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => {
84
- void action.handler();
85
- }, className: action.destructive ? "text-destructive" : undefined, children: [_jsx(action.icon, { className: "mr-2 size-4" }), action.label] })] }, action.label))) })] }))] }, item.to)))] }, section.label))), items.length === 0 && !compact && (_jsx("p", { className: "py-3 text-sm text-muted-foreground", children: search ? "No matching chats" : "No chats yet" }))] }), compact && onViewAll && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: onViewAll, className: "mt-1 h-9 w-fit gap-2 px-2 text-sm font-normal text-muted-foreground [@media(pointer:coarse)]:min-h-11", children: [_jsx(History, { className: "size-4", "aria-hidden": true }), "Conversation history"] }))] }));
125
+ : "Last outside a workspace" })))] })] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Actions for ${item.label}`, className: "mr-1 inline-flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100 [@media(hover:none)]:opacity-100 hover:bg-background", children: _jsx(MoreHorizontal, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onSelect: () => {
126
+ const rawId = runFor(item)?.threadId ??
127
+ item.meta?.conversationId ??
128
+ item.to.split("/chat/")[1]?.split(/[?#]/)[0];
129
+ if (typeof rawId !== "string" || !rawId)
130
+ return;
131
+ const id = rawId;
132
+ void Promise.resolve()
133
+ .then(() => navigator.clipboard.writeText(decodeURIComponent(String(id))))
134
+ .then(() => {
135
+ setCopiedId(id);
136
+ setLoadError(null);
137
+ })
138
+ .catch(() => setLoadError(`Could not copy. Chat ID: ${decodeURIComponent(id)}`));
139
+ }, children: [_jsx(Copy, { className: "size-4" }), "Copy chat ID"] }), Boolean(item.actions?.length) && _jsx(DropdownMenuSeparator, {}), item.actions?.map((action) => (_jsxs(Fragment, { children: [action.separator && _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onSelect: () => {
140
+ void action.handler();
141
+ }, className: action.destructive ? "text-destructive" : undefined, children: [_jsx(action.icon, { className: "mr-2 size-4" }), action.label] })] }, action.label)))] })] })] }, item.to)))] }, section.label))), items.length === 0 && !compact && (_jsx("p", { className: "py-3 text-sm text-muted-foreground", children: search ? "No matching chats" : "No chats yet" }))] }), compact && onViewAll && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: onViewAll, className: "mt-1 h-9 w-fit gap-2 px-2 text-sm font-normal text-muted-foreground [@media(pointer:coarse)]:min-h-11", children: [_jsx(MessagesSquare, { className: "size-4", "aria-hidden": true }), "Conversation history"] }))] }));
86
142
  }
@@ -0,0 +1,3 @@
1
+ export declare function RunningChatsMenu({ onOpen }?: {
2
+ onOpen?: () => void;
3
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useAGUIAdapter } from "../components/ag-ui-runtime-provider.js";
3
+ import { useNavigate } from "react-router";
4
+ import { LoaderCircle, MessageSquare, PauseCircle } from "lucide-react";
5
+ import { useChatRuns, isChatRunActive } from "../lib/chat-runs-store.js";
6
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, } from "../ui/dropdown-menu.js";
7
+ export function RunningChatsMenu({ onOpen } = {}) {
8
+ const runs = useChatRuns((s) => s.runs);
9
+ const navigate = useNavigate();
10
+ const { selectRetainedThread } = useAGUIAdapter();
11
+ const active = Object.values(runs).filter(isChatRunActive);
12
+ if (!active.length)
13
+ return null;
14
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": `${active.length} running conversations`, className: "inline-flex items-center gap-1.5 px-2 text-xs text-primary", children: [_jsx(LoaderCircle, { className: "size-3.5 animate-spin motion-reduce:animate-none" }), _jsx("span", { children: active.length })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "max-w-80", children: [_jsx(DropdownMenuLabel, { children: "Running in this browser" }), active.map((run) => (_jsxs(DropdownMenuItem, { onSelect: () => {
15
+ if (!selectRetainedThread(run.threadId)) {
16
+ navigate(run.conversationUrl ?? `/chat/${encodeURIComponent(run.threadId)}`);
17
+ }
18
+ onOpen?.();
19
+ }, children: [run.status === "waiting" ? (_jsx(PauseCircle, { className: "size-4 shrink-0" })) : (_jsx(MessageSquare, { className: "size-4 shrink-0" })), _jsxs("span", { className: "min-w-0", children: [_jsx("span", { className: "block truncate", children: run.title }), run.status === "waiting" && (_jsx("span", { className: "block text-xs text-muted-foreground", children: "Open to continue" }))] })] }, run.threadId)))] })] }));
20
+ }
@@ -60,12 +60,9 @@ export function SelectionBridge({ children }) {
60
60
  .workbench-preview [data-sidebar-surface="desktop"] nav { padding-right: 16px; }
61
61
  .workbench-preview [data-sidebar-surface="desktop"] { border-right-color: transparent; }
62
62
  [data-connected-navigation="true"] [data-sidebar-surface="desktop"] [data-active-nav-row="true"] {
63
- background: var(--background);
64
63
  border-color: transparent; border-top-right-radius: 0; border-bottom-right-radius: 0;
65
64
  }
66
- ` }), children, anchor && (_jsxs("svg", { "aria-hidden": "true", className: "pointer-events-none absolute z-20", style: { inset: 0, width: anchor.width + anchor.surfaceWidth, height: anchor.navHeight }, viewBox: `0 0 ${anchor.width + anchor.surfaceWidth} ${anchor.navHeight}`, children: [_jsx("path", { fill: "var(--background)", d: `M ${anchor.width},${anchor.top - 7} Q ${anchor.width},${anchor.top} ${anchor.width - 8},${anchor.top}
67
- H ${anchor.rowRight} V ${anchor.top + anchor.height} H ${anchor.width - 8}
68
- Q ${anchor.width},${anchor.top + anchor.height} ${anchor.width},${anchor.top + anchor.height + 7} Z` }), _jsx("path", { fill: "none", stroke: "var(--sidebar-ring)", strokeOpacity: 0.28, strokeWidth: 1, d: `M ${anchor.width + 12},0.5
65
+ ` }), children, anchor && (_jsx("svg", { "aria-hidden": "true", className: "pointer-events-none absolute z-20", style: { inset: 0, width: anchor.width + anchor.surfaceWidth, height: anchor.navHeight }, viewBox: `0 0 ${anchor.width + anchor.surfaceWidth} ${anchor.navHeight}`, children: _jsx("path", { fill: "none", stroke: "var(--sidebar-ring)", strokeOpacity: 0.6, strokeWidth: 1, d: `M ${anchor.width + 12},0.5
69
66
  H ${anchor.width + anchor.surfaceWidth - 12}
70
67
  Q ${anchor.width + anchor.surfaceWidth - 0.5},0.5 ${anchor.width + anchor.surfaceWidth - 0.5},12
71
68
  V ${anchor.navHeight - 12}
@@ -80,5 +77,5 @@ export function SelectionBridge({ children }) {
80
77
  Q ${anchor.left},${anchor.top + 0.5} ${anchor.left + 12},${anchor.top + 0.5}
81
78
  H ${anchor.width - 8}
82
79
  Q ${anchor.width - 0.5},${anchor.top + 0.5} ${anchor.width - 0.5},${anchor.top - 7}
83
- V 12 Q ${anchor.width - 0.5},0.5 ${anchor.width + 12},0.5 Z` })] }))] }));
80
+ V 12 Q ${anchor.width - 0.5},0.5 ${anchor.width + 12},0.5 Z` }) }))] }));
84
81
  }
@@ -1,4 +1,3 @@
1
- import type { NavItem } from "../lib/nav-config.js";
2
1
  export declare function normalizeWorkbenchPath(path: string): string;
3
2
  export declare function useWorkbenchState(chatRoute: boolean): {
4
3
  panelOpen: boolean;
@@ -38,7 +37,7 @@ export declare function useWorkbenchState(chatRoute: boolean): {
38
37
  label: string;
39
38
  tree?: boolean;
40
39
  icon?: import("lucide-react").LucideIcon;
41
- items: NavItem[];
40
+ items: import("../index.js").NavItem[];
42
41
  priority?: number;
43
42
  defaultCollapsed?: boolean;
44
43
  to?: string;
@@ -4,22 +4,12 @@ import { useAuiState } from "@assistant-ui/react";
4
4
  import { useEffect, useMemo, useRef, useState } from "react";
5
5
  import { Button } from "@iloveagents/foundry-web-primitives";
6
6
  import { useSidebarStore, useChatBubbleStore, useToolPanelStore, useNewConversation, useNavStore, useAppStore, } from "../index.js";
7
- import { History, Settings, Layers } from "lucide-react";
7
+ import { MessagesSquare, Settings, Layers } from "lucide-react";
8
8
  import { useChatWidth } from "./use-chat-width.js";
9
+ import { findNavItem } from "../lib/nav-config.js";
9
10
  export function normalizeWorkbenchPath(path) {
10
11
  return path === "/" ? path : path.replace(/\/+$/, "");
11
12
  }
12
- function findExactWorkbenchItem(items, pathname) {
13
- const target = normalizeWorkbenchPath(pathname);
14
- for (const item of items) {
15
- if (normalizeWorkbenchPath(item.to) === target)
16
- return item;
17
- const nested = item.children && findExactWorkbenchItem(item.children, pathname);
18
- if (nested)
19
- return nested;
20
- }
21
- return undefined;
22
- }
23
13
  function useWorkbenchNavigation() {
24
14
  const navGroups = useNavStore((s) => s.config);
25
15
  const workspaceGroups = useMemo(() => {
@@ -33,9 +23,12 @@ function useWorkbenchNavigation() {
33
23
  const space = workspaceGroups[0];
34
24
  const root = space.items.find((item) => item.to === space.focusOn) ?? space.items[0];
35
25
  return [
26
+ ...navGroups
27
+ .filter((group) => group.meta?.showInWorkspaceNavigation)
28
+ .map((group) => ({ ...group, priority: 1100 })),
36
29
  {
37
30
  ...space,
38
- label: "Spaces",
31
+ label: "All spaces",
39
32
  icon: Layers,
40
33
  priority: 1000,
41
34
  items: root
@@ -56,7 +49,7 @@ function useWorkbenchNavigation() {
56
49
  ...navGroups
57
50
  .filter((group) => !["recent-chats", "pinned-chats"].includes(String(group.meta?.type)))
58
51
  .map((group) => group.meta?.type === "spaces-workspaces"
59
- ? { ...group, label: "Spaces", icon: Layers }
52
+ ? { ...group, label: "All spaces", icon: Layers, createActions: undefined }
60
53
  : group.label === "Admin"
61
54
  ? { ...group, icon: Settings }
62
55
  : group.label === "Activity"
@@ -72,9 +65,13 @@ export function useWorkbenchState(chatRoute) {
72
65
  const chatOnly = chatRoute && !panelOpen;
73
66
  const location = useLocation();
74
67
  const { navGroups, workspaceGroups, staticNavigationGroups } = useWorkbenchNavigation();
75
- const routeItem = useMemo(() => navGroups
76
- .map((group) => findExactWorkbenchItem(group.items, location.pathname))
77
- .find((item) => item !== undefined), [location.pathname, navGroups]);
68
+ const routeItem = useMemo(() => {
69
+ const item = findNavItem(navGroups, location.pathname + location.search)?.item;
70
+ return item &&
71
+ normalizeWorkbenchPath(item.to.split("?")[0]) === normalizeWorkbenchPath(location.pathname)
72
+ ? item
73
+ : undefined;
74
+ }, [location.pathname, location.search, navGroups]);
78
75
  const pageLabel = useAppStore((s) => s.navContext.label);
79
76
  const entityId = routeItem?.meta?.spacesEntityId;
80
77
  const chatWidth = useChatWidth();
@@ -108,7 +105,7 @@ export function useWorkbenchState(chatRoute) {
108
105
  const openHistory = () => {
109
106
  setHistoryOpen(true);
110
107
  };
111
- const historyShortcut = (_jsxs(Button, { variant: "ghost", size: "sm", onClick: openHistory, className: "h-9 w-fit gap-2 px-2 text-sm font-normal text-muted-foreground [@media(pointer:coarse)]:min-h-11", children: [_jsx(History, { className: "size-4", "aria-hidden": true }), "Conversation history"] }));
108
+ const historyShortcut = (_jsxs(Button, { variant: "ghost", size: "sm", onClick: openHistory, className: "h-9 w-fit gap-2 px-2 text-sm font-normal text-muted-foreground [@media(pointer:coarse)]:min-h-11", children: [_jsx(MessagesSquare, { className: "size-4", "aria-hidden": true }), "Conversation history"] }));
112
109
  const toggleNavigation = useSidebarStore((s) => s.toggleMobile);
113
110
  useEffect(() => {
114
111
  if (panelOpen) {
@@ -4,7 +4,7 @@ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuIte
4
4
  import { ChatHomeStartersSlot } from "../components/chat-slots.js";
5
5
  import { Layers } from "lucide-react";
6
6
  export function WelcomeIntro({ navGroups, historyShortcut, }) {
7
- return (_jsxs("div", { className: "mb-4 text-center", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: "What would you like to get done?" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Find information, create or edit content, and run actions across your spaces." }), _jsx("div", { className: "mx-auto mt-4 max-w-sm text-left", children: _jsx(ChatHomeStartersSlot, { priority: 10 }) }), _jsxs("div", { className: "mt-4 flex flex-wrap items-center justify-center gap-2", children: [historyShortcut, navGroups.some((group) => group.meta?.type === "spaces-workspaces" && group.createActions?.length) && (_jsx("div", { children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", className: "h-8 gap-2 px-3 text-xs font-normal text-muted-foreground [@media(pointer:coarse)]:min-h-11", children: [_jsx(Layers, { className: "size-3.5", "aria-hidden": "true" }), "Create a space"] }) }), _jsx(DropdownMenuContent, { align: "center", children: navGroups
7
+ return (_jsxs("div", { className: "mb-4 text-center", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: "What would you like to get done?" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Find information, create or edit content, and run actions across your spaces." }), _jsx("div", { className: "mx-auto mt-4 max-w-sm text-left", children: _jsx(ChatHomeStartersSlot, { priority: 10 }) }), _jsxs("div", { className: "mt-4 flex flex-wrap items-center justify-center gap-2", children: [historyShortcut, navGroups.some((group) => group.meta?.type === "spaces-workspaces" && group.createActions?.length) && (_jsx("div", { children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", className: "h-9 gap-2 px-2 text-sm font-normal text-muted-foreground [@media(pointer:coarse)]:min-h-11", children: [_jsx(Layers, { className: "size-4", "aria-hidden": "true" }), "Create a space"] }) }), _jsx(DropdownMenuContent, { align: "center", children: navGroups
8
8
  .filter((group) => group.meta?.type === "spaces-workspaces")
9
9
  .flatMap((group) => group.createActions ?? [])
10
10
  .map((action) => (_jsx(DropdownMenuItem, { onSelect: () => action.handler(), children: action.label }, action.id))) })] }) }))] })] }));
@@ -101,7 +101,6 @@ export function WorkbenchStyles() {
101
101
  }
102
102
  .workbench-preview {
103
103
  --workbench-header-height: 60px;
104
- --sidebar: color-mix(in srgb, var(--background) 98.5%, var(--foreground) 1.5%);
105
104
  background: var(--sidebar);
106
105
  --workbench-outline: color-mix(in srgb, var(--sidebar-ring) 28%, transparent);
107
106
  padding: 8px 8px 8px 0;
@@ -255,15 +254,14 @@ export function WorkbenchStyles() {
255
254
  min-height: 32px;
256
255
  gap: 8px;
257
256
  }
258
- [data-workspace-navigation] [data-nav-group-label="Spaces"] > :first-child,
259
257
  .workbench-preview [data-sidebar-surface] nav > [data-nav-group-label]:first-child > div:has(> [data-nav-group-header]) {
260
258
  padding-top: 0;
261
259
  }
262
- [data-workspace-navigation] [data-nav-group-label="Spaces"] [data-nav-depth="0"] > button {
263
- font-size: 15px;
260
+ [data-workspace-navigation] [data-nav-group-label="All spaces"] [data-nav-depth="0"] > button {
261
+ font-size: 14px;
264
262
  font-weight: 600;
265
- letter-spacing: -0.015em;
266
- line-height: 22px;
263
+ letter-spacing: normal;
264
+ line-height: 20px;
267
265
  }
268
266
  [data-workspace-navigation] [data-nav-group-label="Recent chats"] > :first-child {
269
267
  padding-top: 10px;
@@ -271,6 +269,38 @@ export function WorkbenchStyles() {
271
269
  [data-workspace-navigation] [data-nav-group-label="Content"] {
272
270
  margin-top: 0;
273
271
  }
272
+ .workbench-preview [data-nav-group-label="All spaces"] > div:has(> [data-nav-group-header]) {
273
+ padding-top: 8px;
274
+ }
275
+ .workbench-preview [data-nav-group-label="All spaces"] [data-nav-group-header] {
276
+ height: 32px;
277
+ min-height: 32px;
278
+ padding-top: 0;
279
+ padding-bottom: 0;
280
+ }
281
+ .workbench-preview [data-nav-group-label="All spaces"] [data-nav-group-items] {
282
+ animation: none;
283
+ }
284
+ /* The first utility row shares the heading line in both scopes. */
285
+ .workbench-preview [data-sidebar-surface]:not([data-sidebar-collapsed]) nav:has(> [data-nav-group-label="Activity"]:first-child) {
286
+ padding-top: 8px;
287
+ }
288
+ .workbench-preview [data-sidebar-surface]:not([data-sidebar-collapsed]) [data-nav-group-label="Activity"] [data-nav-depth="0"] {
289
+ padding-left: 12px;
290
+ }
291
+ .workbench-preview [data-nav-group-label="Activity"] [data-nav-twisty-cell]:not(:has([data-nav-twisty])) {
292
+ display: none;
293
+ }
294
+ .workbench-preview[data-workspace-navigation]:not(:has([data-page-title-row])) [data-chat-empty-state] {
295
+ padding-top: 28px;
296
+ }
297
+ .workbench-preview[data-workspace-navigation] [data-preview-entity-header] > [data-entity-header-row] {
298
+ padding-top: 24px;
299
+ min-height: 76px;
300
+ }
301
+ .workbench-preview[data-workspace-navigation] [data-entity-header-identity]:not(:has([aria-label="Page location"])) {
302
+ padding-top: 18px;
303
+ }
274
304
 
275
305
  [data-workspace-navigation] [data-sidebar-surface]:not([data-sidebar-collapsed]) [data-nav-group-label="Content"] button[data-nav-depth],
276
306
  [data-workspace-navigation] [data-sidebar-surface]:not([data-sidebar-collapsed]) [data-nav-group-label="Content"] div[data-nav-depth] > button:not([data-nav-twisty]) {
@@ -280,6 +310,24 @@ export function WorkbenchStyles() {
280
310
  left: calc(12px + var(--nav-depth, 0) * 16px);
281
311
  }
282
312
 
313
+ @media (pointer: fine) {
314
+ .workbench-preview [data-sidebar-surface]:not([data-sidebar-collapsed]) [data-nav-depth] {
315
+ height: 32px;
316
+ min-height: 32px;
317
+ padding-top: 0;
318
+ padding-bottom: 0;
319
+ }
320
+ .workbench-preview [data-sidebar-surface]:not([data-sidebar-collapsed]) div[data-nav-depth] > button:not([data-nav-twisty]) {
321
+ height: 30px;
322
+ min-height: 30px;
323
+ padding-top: 0;
324
+ padding-bottom: 0;
325
+ }
326
+ .workbench-preview:not([data-workspace-navigation]) [data-sidebar-surface]:not([data-sidebar-collapsed]) div[data-nav-depth="0"] > button:not([data-nav-twisty]) {
327
+ min-height: 30px;
328
+ }
329
+ }
330
+
283
331
  @media (pointer: coarse) {
284
332
  .workbench-preview [data-conversation-row],
285
333
  .workbench-preview [data-sidebar-surface]:not([data-sidebar-collapsed]) [data-nav-depth] {
@@ -39,5 +39,5 @@ export function WorkbenchPreview({ page, chatOnly: chatRoute = false, }) {
39
39
  }, children: [_jsx(WorkbenchChatHeader, { collapsed: collapsed, running: running, chatWidth: chatWidth, buttonClass: buttonClass, toggleNavigation: toggleNavigation, setCollapsed: setCollapsed, showHistory: showHistory, startChat: startChat, returnToChat: returnToChat, openHistory: openHistory, chatOnly: chatOnly, setContentCollapsed: setContentCollapsed }), !collapsed && showHistory && (_jsx(ConversationHistory, { groups: navGroups, workspaceId: workspaceId, onClose: returnToChat, showBack: true })), !chatWidth.compact && !collapsed && !contentCollapsed && (_jsx(ChatResizeHandle, { chatWidth: chatWidth })), _jsx("div", { className: "min-h-0 flex-1 flex-col", style: {
40
40
  display: collapsed || showHistory ? "none" : "flex",
41
41
  paddingBottom: spaciousChat && emptyChat && !historyOpen ? "clamp(32px, 10vh, 96px)" : undefined,
42
- }, children: _jsx(ChatContent, { centerComposer: spaciousChat && emptyChat && !historyOpen, composerIntro: spaciousChat && emptyChat ? (_jsx(WelcomeIntro, { navGroups: navGroups, historyShortcut: emptyChatFooter })) : undefined, compactComposer: !spaciousChat, hideCurrentPageBadge: true, showPinButton: false, starterSuggestions: [], emptyState: _jsx(ChatEmptyState, { pageLabel: pageLabel, showHomeStarters: !spaciousChat, children: emptyChatFooter }) }) })] }), _jsx(WorkbenchContentPane, { contentHidden: contentHidden, panelOpen: panelOpen, chatWidth: chatWidth, contentCollapsed: contentCollapsed, collapsed: collapsed, buttonClass: buttonClass, setCollapsed: setCollapsed, setContentCollapsed: setContentCollapsed, closePanel: closePanel, page: page }), contentCollapsed && !chatOnly && !chatWidth.compact && (_jsx("aside", { "aria-label": "Collapsed content", className: "flex w-11 shrink-0 flex-col items-center", style: { width: 44 }, children: _jsx("div", { className: "flex h-full w-full flex-col items-center", "data-chat-rail": true, children: _jsx("div", { className: "flex items-center justify-center", style: { height: 60 }, children: _jsx(TooltipIconButton, { tooltip: "Expand content", className: buttonClass, "aria-label": "Expand content", onClick: () => setContentCollapsed(false), children: _jsx(FileText, { size: 18 }) }) }) }) }))] })] })] }));
42
+ }, children: _jsx(ChatContent, { centerComposer: spaciousChat && emptyChat && !historyOpen, composerIntro: spaciousChat && emptyChat ? (_jsx(WelcomeIntro, { navGroups: navGroups, historyShortcut: emptyChatFooter })) : undefined, compactComposer: !spaciousChat, starterSuggestions: [], emptyState: _jsx(ChatEmptyState, { pageLabel: pageLabel, showHomeStarters: !spaciousChat, children: emptyChatFooter }) }) })] }), _jsx(WorkbenchContentPane, { contentHidden: contentHidden, panelOpen: panelOpen, chatWidth: chatWidth, contentCollapsed: contentCollapsed, collapsed: collapsed, buttonClass: buttonClass, setCollapsed: setCollapsed, setContentCollapsed: setContentCollapsed, closePanel: closePanel, page: page }), contentCollapsed && !chatOnly && !chatWidth.compact && (_jsx("aside", { "aria-label": "Collapsed content", className: "flex w-11 shrink-0 flex-col items-center", style: { width: 44 }, children: _jsx("div", { className: "flex h-full w-full flex-col items-center", "data-chat-rail": true, children: _jsx("div", { className: "flex items-center justify-center", style: { height: 60 }, children: _jsx(TooltipIconButton, { tooltip: "Expand content", className: buttonClass, "aria-label": "Expand content", onClick: () => setContentCollapsed(false), children: _jsx(FileText, { size: 18 }) }) }) }) }))] })] })] }));
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-web-ui",
3
- "version": "0.29.1",
3
+ "version": "0.31.0",
4
4
  "license": "MIT",
5
5
  "description": "React agent UI core for Foundry UI — chat, composer, AG-UI adapter for assistant-ui, tool cards, panels, sidebar, theme runtime, and UI stores.",
6
6
  "keywords": [
@@ -80,8 +80,8 @@
80
80
  "recharts": "^3.10.1",
81
81
  "remark-gfm": "^4.0.0",
82
82
  "tailwind-merge": "^3.5.0",
83
- "@iloveagents/foundry-agent": "^0.29.1",
84
- "@iloveagents/foundry-web-primitives": "^0.29.1"
83
+ "@iloveagents/foundry-agent": "^0.31.0",
84
+ "@iloveagents/foundry-web-primitives": "^0.31.0"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@ag-ui/client": "^0.0.52",