@truefoundry/trueforge-ui 0.3.0-rc.2 → 0.3.0-rc.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +18 -10
  3. package/dist/{AgentCodeSnippets-637HQUXD.js → AgentCodeSnippets-U6KQWVBJ.js} +38 -23
  4. package/dist/AgentCodeSnippets-U6KQWVBJ.js.map +1 -0
  5. package/dist/AgentMetricChart-3D6FUFO6.js +15 -0
  6. package/dist/{AgentOverview-3FJ5EE6N.js → AgentOverview-RLJ6HZCN.js} +7 -7
  7. package/dist/{AgentSessionEventTimeline-VELWUYPR.js → AgentSessionEventTimeline-CDXRRUZQ.js} +8 -8
  8. package/dist/{AgentSessionEventTimeline-VELWUYPR.js.map → AgentSessionEventTimeline-CDXRRUZQ.js.map} +1 -1
  9. package/dist/{AgentSessionEventTimelineChart-CUKETHWM.js → AgentSessionEventTimelineChart-S2WX6ZEA.js} +12 -12
  10. package/dist/AgentSessionEventTimelineChart-S2WX6ZEA.js.map +1 -0
  11. package/dist/{AgentSessions-T7MOGOTZ.js → AgentSessions-UI3L7XY2.js} +72 -24
  12. package/dist/AgentSessions-UI3L7XY2.js.map +1 -0
  13. package/dist/{ConnectorSettings-ESZ2RSRG.js → ConnectorSettings-OIGAC2HU.js} +156 -116
  14. package/dist/ConnectorSettings-OIGAC2HU.js.map +1 -0
  15. package/dist/{DockLayout-NLFNU6F2.js → DockLayout-J5BRKMJZ.js} +10 -10
  16. package/dist/{DrawerLayout-PR3SMKA6.js → DrawerLayout-65YHGHIF.js} +13 -11
  17. package/dist/DrawerLayout-65YHGHIF.js.map +1 -0
  18. package/dist/{ModelSettings-LYW64IRR.js → ModelSettings-VP6WCMGT.js} +10 -10
  19. package/dist/{ModelSettings-LYW64IRR.js.map → ModelSettings-VP6WCMGT.js.map} +1 -1
  20. package/dist/OpenUiFenceBlock-UTDCTNTM.js +9 -0
  21. package/dist/{SandboxSettings-DF64LHYI.js → SandboxSettings-GTZT7LD6.js} +9 -9
  22. package/dist/SchedulesPage-ARWU7BZF.js +15 -0
  23. package/dist/{SettingsBuilder-LSXK2VN4.js → SettingsBuilder-A4BPYIFZ.js} +8 -8
  24. package/dist/{ShellRouteSync-B22IAV2W.js → ShellRouteSync-SSLGM35F.js} +157 -22
  25. package/dist/ShellRouteSync-SSLGM35F.js.map +1 -0
  26. package/dist/{SidebarLayout-XW6LXB7R.js → SidebarLayout-MFDOGAVJ.js} +74 -53
  27. package/dist/SidebarLayout-MFDOGAVJ.js.map +1 -0
  28. package/dist/{SkillSettings-64VXUO6J.js → SkillSettings-WQPUQ5TE.js} +18 -13
  29. package/dist/SkillSettings-WQPUQ5TE.js.map +1 -0
  30. package/dist/{TrueForgeUIWithRouter-3TSLV22Q.js → TrueForgeUIWithRouter-5CDICMCE.js} +9 -9
  31. package/dist/{WidgetLayout-Q5P7PYSJ.js → WidgetLayout-HE7E4UL5.js} +10 -10
  32. package/dist/{chunk-SQGT43Z3.js → chunk-2BDTG544.js} +21 -4
  33. package/dist/chunk-2BDTG544.js.map +1 -0
  34. package/dist/{chunk-YQO2NMJ3.js → chunk-2OKGEU6X.js} +4425 -2982
  35. package/dist/chunk-2OKGEU6X.js.map +1 -0
  36. package/dist/{chunk-FQK2XVVE.js → chunk-6CFZHEYH.js} +225 -72
  37. package/dist/chunk-6CFZHEYH.js.map +1 -0
  38. package/dist/{chunk-QC42MLAK.js → chunk-7AAO4UDQ.js} +4 -3
  39. package/dist/chunk-7AAO4UDQ.js.map +1 -0
  40. package/dist/chunk-E4GVP6PM.js +195 -0
  41. package/dist/chunk-E4GVP6PM.js.map +1 -0
  42. package/dist/{chunk-LGRHHFHN.js → chunk-F7ZAQIRE.js} +166 -45
  43. package/dist/chunk-F7ZAQIRE.js.map +1 -0
  44. package/dist/{chunk-VJ7BZGAF.js → chunk-GTTMLDCI.js} +2 -2
  45. package/dist/{chunk-5I2COQNL.js → chunk-IOPHQEUY.js} +13 -11
  46. package/dist/chunk-IOPHQEUY.js.map +1 -0
  47. package/dist/{chunk-G2TUAD65.js → chunk-KCYBMKQL.js} +235 -108
  48. package/dist/chunk-KCYBMKQL.js.map +1 -0
  49. package/dist/{chunk-H6WTY5PM.js → chunk-MAA7U4RF.js} +17 -227
  50. package/dist/chunk-MAA7U4RF.js.map +1 -0
  51. package/dist/{chunk-GXYAOAK5.js → chunk-MJULWIPI.js} +224 -162
  52. package/dist/chunk-MJULWIPI.js.map +1 -0
  53. package/dist/chunk-P7J2ABEP.js +587 -0
  54. package/dist/chunk-P7J2ABEP.js.map +1 -0
  55. package/dist/{chunk-VUMGMGKZ.js → chunk-TGKQRK3S.js} +52 -8
  56. package/dist/chunk-TGKQRK3S.js.map +1 -0
  57. package/dist/{chunk-I3AL54MA.js → chunk-VXKNS7FH.js} +28 -24
  58. package/dist/chunk-VXKNS7FH.js.map +1 -0
  59. package/dist/chunk-XO3FYN2W.js +517 -0
  60. package/dist/chunk-XO3FYN2W.js.map +1 -0
  61. package/dist/{createTrueFoundryServer-CmZnBh_l.d.ts → createTrueFoundryServer-B_FYhSdn.d.ts} +8 -5
  62. package/dist/index.d.ts +300 -89
  63. package/dist/index.js +65 -488
  64. package/dist/index.js.map +1 -1
  65. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +44 -13
  66. package/dist/plugins/trueforge-agent-server-adapter/index.js +73 -37
  67. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  68. package/dist/styles.css +1 -1
  69. package/package.json +3 -3
  70. package/dist/AgentCodeSnippets-637HQUXD.js.map +0 -1
  71. package/dist/AgentMetricChart-4FYECRIN.js +0 -15
  72. package/dist/AgentSessionEventTimelineChart-CUKETHWM.js.map +0 -1
  73. package/dist/AgentSessions-T7MOGOTZ.js.map +0 -1
  74. package/dist/ConnectorSettings-ESZ2RSRG.js.map +0 -1
  75. package/dist/DrawerLayout-PR3SMKA6.js.map +0 -1
  76. package/dist/OpenUiFenceBlock-JEPNPJ7U.js +0 -9
  77. package/dist/SchedulesPage-WQU4H25F.js +0 -15
  78. package/dist/ShellRouteSync-B22IAV2W.js.map +0 -1
  79. package/dist/SidebarLayout-XW6LXB7R.js.map +0 -1
  80. package/dist/SkillSettings-64VXUO6J.js.map +0 -1
  81. package/dist/chunk-5I2COQNL.js.map +0 -1
  82. package/dist/chunk-BWHOZFIV.js +0 -587
  83. package/dist/chunk-BWHOZFIV.js.map +0 -1
  84. package/dist/chunk-FQK2XVVE.js.map +0 -1
  85. package/dist/chunk-G2TUAD65.js.map +0 -1
  86. package/dist/chunk-GXYAOAK5.js.map +0 -1
  87. package/dist/chunk-H6WTY5PM.js.map +0 -1
  88. package/dist/chunk-I3AL54MA.js.map +0 -1
  89. package/dist/chunk-LGRHHFHN.js.map +0 -1
  90. package/dist/chunk-NHHSZB5N.js +0 -74
  91. package/dist/chunk-NHHSZB5N.js.map +0 -1
  92. package/dist/chunk-QC42MLAK.js.map +0 -1
  93. package/dist/chunk-SFZNIO6U.js +0 -18
  94. package/dist/chunk-SFZNIO6U.js.map +0 -1
  95. package/dist/chunk-SQGT43Z3.js.map +0 -1
  96. package/dist/chunk-VUMGMGKZ.js.map +0 -1
  97. package/dist/chunk-YQO2NMJ3.js.map +0 -1
  98. /package/dist/{AgentMetricChart-4FYECRIN.js.map → AgentMetricChart-3D6FUFO6.js.map} +0 -0
  99. /package/dist/{AgentOverview-3FJ5EE6N.js.map → AgentOverview-RLJ6HZCN.js.map} +0 -0
  100. /package/dist/{DockLayout-NLFNU6F2.js.map → DockLayout-J5BRKMJZ.js.map} +0 -0
  101. /package/dist/{OpenUiFenceBlock-JEPNPJ7U.js.map → OpenUiFenceBlock-UTDCTNTM.js.map} +0 -0
  102. /package/dist/{SandboxSettings-DF64LHYI.js.map → SandboxSettings-GTZT7LD6.js.map} +0 -0
  103. /package/dist/{SchedulesPage-WQU4H25F.js.map → SchedulesPage-ARWU7BZF.js.map} +0 -0
  104. /package/dist/{SettingsBuilder-LSXK2VN4.js.map → SettingsBuilder-A4BPYIFZ.js.map} +0 -0
  105. /package/dist/{TrueForgeUIWithRouter-3TSLV22Q.js.map → TrueForgeUIWithRouter-5CDICMCE.js.map} +0 -0
  106. /package/dist/{WidgetLayout-Q5P7PYSJ.js.map → WidgetLayout-HE7E4UL5.js.map} +0 -0
  107. /package/dist/{chunk-VJ7BZGAF.js.map → chunk-GTTMLDCI.js.map} +0 -0
@@ -0,0 +1,517 @@
1
+ import {
2
+ BottomSheet,
3
+ DropdownMenuItem,
4
+ SearchInput_default,
5
+ canReuseMutableShell,
6
+ readThreadAgentName,
7
+ themePortalRoot,
8
+ threadListIndicesByRecency,
9
+ threadListItemIsMutable,
10
+ useIsMobile,
11
+ useResourcePermissions,
12
+ useSlot
13
+ } from "./chunk-2OKGEU6X.js";
14
+ import {
15
+ useSearchAgentsList
16
+ } from "./chunk-E4GVP6PM.js";
17
+ import {
18
+ Icon,
19
+ auiButtonClass,
20
+ useCompactLayout
21
+ } from "./chunk-MAA7U4RF.js";
22
+ import {
23
+ libraryAgentId,
24
+ useOptionalServer,
25
+ useOptionalShellMode
26
+ } from "./chunk-6CFZHEYH.js";
27
+ import {
28
+ cn
29
+ } from "./chunk-P7J2ABEP.js";
30
+
31
+ // src/containers/ThreadListContainer.tsx
32
+ import {
33
+ ThreadListItemByIndexProvider,
34
+ ThreadListItemMorePrimitive,
35
+ ThreadListItemPrimitive,
36
+ ThreadListPrimitive,
37
+ useAui,
38
+ useAuiState
39
+ } from "@assistant-ui/react";
40
+ import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
41
+
42
+ // src/atoms/AgentHistoryFilterButton.tsx
43
+ import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
44
+ import { createPortal } from "react-dom";
45
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
46
+ function AgentHistoryFilterButton() {
47
+ const shell = useOptionalShellMode();
48
+ const server = useOptionalServer();
49
+ const isMobile = useIsMobile();
50
+ const compact = useCompactLayout();
51
+ const useSheet = isMobile || compact;
52
+ const [open, setOpen] = useState(false);
53
+ const [query, setQuery] = useState("");
54
+ const [menuPos, setMenuPos] = useState(null);
55
+ const buttonRef = useRef(null);
56
+ const menuRef = useRef(null);
57
+ const menuId = useId();
58
+ const enabled = shell?.isLibraryEnabled === true && server != null;
59
+ const selected = shell?.historyAgentFilter ?? null;
60
+ useEffect(() => {
61
+ if (!open) setQuery("");
62
+ }, [open]);
63
+ const { agents, isInitialLoading, isSearching, loadingMore, hasMore, listRef, sentinelRef } = useSearchAgentsList({
64
+ enabled: open && enabled,
65
+ query
66
+ });
67
+ useLayoutEffect(() => {
68
+ if (!open || useSheet) {
69
+ setMenuPos(null);
70
+ return;
71
+ }
72
+ const update = () => {
73
+ const rect = buttonRef.current?.getBoundingClientRect();
74
+ if (!rect) return;
75
+ setMenuPos({ top: rect.top, left: rect.right + 4 });
76
+ };
77
+ update();
78
+ window.addEventListener("resize", update);
79
+ window.addEventListener("scroll", update, true);
80
+ return () => {
81
+ window.removeEventListener("resize", update);
82
+ window.removeEventListener("scroll", update, true);
83
+ };
84
+ }, [open, useSheet]);
85
+ useEffect(() => {
86
+ if (!open || useSheet) return;
87
+ const handler = (e) => {
88
+ const target = e.target;
89
+ if (buttonRef.current?.contains(target) || menuRef.current?.contains(target)) return;
90
+ setOpen(false);
91
+ };
92
+ document.addEventListener("mousedown", handler);
93
+ return () => document.removeEventListener("mousedown", handler);
94
+ }, [open, useSheet]);
95
+ if (!enabled) return null;
96
+ const pick = (filter) => {
97
+ if (shell?.isComposerEnabled === true) {
98
+ shell.openDraft();
99
+ } else {
100
+ shell?.openLibraryHome();
101
+ }
102
+ shell?.setHistoryAgentFilter(filter);
103
+ setOpen(false);
104
+ };
105
+ const filterBody = /* @__PURE__ */ jsxs(Fragment, { children: [
106
+ /* @__PURE__ */ jsxs("div", { className: "p-1", onMouseDown: (e) => e.stopPropagation(), children: [
107
+ /* @__PURE__ */ jsx(SearchInput_default, { query, setQuery, placeholder: "Search agents" }),
108
+ isSearching ? /* @__PURE__ */ jsx("p", { className: "text-text-secondary px-1 pt-1 text-[11px]", role: "status", children: "Searching\u2026" }) : null
109
+ ] }),
110
+ /* @__PURE__ */ jsxs(
111
+ "div",
112
+ {
113
+ ref: listRef,
114
+ className: cn("mt-1 overflow-y-auto", useSheet ? "min-h-0 flex-1 px-1 pb-2" : "min-h-48 max-h-64"),
115
+ children: [
116
+ query.trim() === "" ? /* @__PURE__ */ jsxs(
117
+ DropdownMenuItem,
118
+ {
119
+ className: cn(
120
+ "justify-between",
121
+ selected == null && "bg-dropdown-selected-item-bg text-dropdown-selected-item-text"
122
+ ),
123
+ onClick: () => pick(null),
124
+ children: [
125
+ "All chats",
126
+ selected == null ? /* @__PURE__ */ jsx(Icon, { name: "check", className: "size-3.5 shrink-0" }) : null
127
+ ]
128
+ }
129
+ ) : null,
130
+ isInitialLoading ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-center text-xs text-text-secondary", children: "Loading\u2026" }) : agents.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-text-secondary px-2 py-6 text-center text-xs", role: "status", children: query.trim() ? `No agents match "${query.trim()}".` : "No agents yet." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
131
+ agents.map((agent) => {
132
+ const id = libraryAgentId(agent);
133
+ const active = selected?.agentId === id;
134
+ return /* @__PURE__ */ jsxs(
135
+ DropdownMenuItem,
136
+ {
137
+ className: cn(
138
+ "justify-between gap-2 text-left",
139
+ active && "bg-dropdown-selected-item-bg text-dropdown-selected-item-text"
140
+ ),
141
+ onClick: () => pick({ agentId: id, agentName: agent.name, intent: "history" }),
142
+ children: [
143
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: agent.name }),
144
+ active ? /* @__PURE__ */ jsx(Icon, { name: "check", className: "size-3.5 shrink-0" }) : null
145
+ ]
146
+ },
147
+ id
148
+ );
149
+ }),
150
+ hasMore ? /* @__PURE__ */ jsx("div", { ref: sentinelRef, className: "flex h-6 shrink-0 items-center justify-center", "aria-hidden": true, children: loadingMore ? /* @__PURE__ */ jsx("span", { className: "text-text-secondary text-[11px]", role: "status", children: "Loading more\u2026" }) : null }) : null
151
+ ] })
152
+ ]
153
+ }
154
+ )
155
+ ] });
156
+ return /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
157
+ /* @__PURE__ */ jsxs(
158
+ "button",
159
+ {
160
+ ref: buttonRef,
161
+ type: "button",
162
+ "aria-label": selected != null ? `Filter chat history by agent (${selected.agentName})` : "Filter chat history by agent",
163
+ "aria-haspopup": useSheet ? "dialog" : "menu",
164
+ "aria-expanded": open,
165
+ "aria-controls": open ? menuId : void 0,
166
+ title: "Filter by agent",
167
+ className: auiButtonClass({
168
+ variant: "ghost",
169
+ size: "icon",
170
+ className: cn(
171
+ "relative size-7 shrink-0 text-text-secondary hover:bg-ghost-button-hover hover:text-ghost-button-text",
172
+ selected != null && "text-text-primary"
173
+ )
174
+ }),
175
+ onClick: () => setOpen((v) => !v),
176
+ children: [
177
+ /* @__PURE__ */ jsx(Icon, { name: "funnel", className: "size-3.5" }),
178
+ selected != null ? /* @__PURE__ */ jsx(
179
+ "span",
180
+ {
181
+ className: "bg-primary-button-bg absolute top-1 right-1 size-1.5 rounded-full",
182
+ "aria-hidden": true,
183
+ "data-testid": "history-filter-active-dot"
184
+ }
185
+ ) : null
186
+ ]
187
+ }
188
+ ),
189
+ useSheet && open ? /* @__PURE__ */ jsx(BottomSheet, { open: true, onOpenChange: setOpen, id: menuId, "aria-label": "Filter agents", children: /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col p-2", role: "menu", children: filterBody }) }) : null,
190
+ !useSheet && open && menuPos != null ? createPortal(
191
+ /* @__PURE__ */ jsx(
192
+ "div",
193
+ {
194
+ ref: menuRef,
195
+ id: menuId,
196
+ role: "menu",
197
+ "aria-label": "Filter agents",
198
+ style: { top: menuPos.top, left: menuPos.left },
199
+ className: "font-sans-flex fixed z-50 w-56 rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md",
200
+ children: filterBody
201
+ }
202
+ ),
203
+ themePortalRoot(buttonRef.current)
204
+ ) : null
205
+ ] });
206
+ }
207
+
208
+ // src/containers/ThreadListContainer.tsx
209
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
210
+ var deleteItemClass = "flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-failure-bg outline-none transition-colors hover:bg-failure-bg/12 hover:text-failure-bg focus:bg-failure-bg/12 focus:text-failure-bg data-[highlighted]:bg-failure-bg/12 data-[highlighted]:text-failure-bg";
211
+ function ThreadListItemDeleteMenu({ disabled }) {
212
+ const PermissionGuard = useSlot("PermissionGuard");
213
+ const compact = useCompactLayout();
214
+ const isMobile = useIsMobile();
215
+ const [sheetOpen, setSheetOpen] = useState2(false);
216
+ const [portalContainer, setPortalContainer] = useState2();
217
+ const useSheet = isMobile || compact;
218
+ const setTriggerElement = useCallback((element) => {
219
+ const themeRoot = element?.closest(".aui-theme-root");
220
+ setPortalContainer(themeRoot instanceof HTMLElement ? themeRoot : void 0);
221
+ }, []);
222
+ const moreButtonClass = auiButtonClass({
223
+ variant: "ghost",
224
+ size: "icon",
225
+ className: "size-7 shrink-0 text-text-secondary hover:bg-transparent hover:text-text-primary"
226
+ });
227
+ if (useSheet) {
228
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
229
+ /* @__PURE__ */ jsx2(
230
+ "button",
231
+ {
232
+ type: "button",
233
+ "aria-label": "Session actions",
234
+ title: "Session actions",
235
+ "aria-haspopup": "dialog",
236
+ "aria-expanded": sheetOpen,
237
+ className: moreButtonClass,
238
+ onClick: () => setSheetOpen(true),
239
+ children: /* @__PURE__ */ jsx2(Icon, { name: "ellipsis", className: "size-3.5" })
240
+ }
241
+ ),
242
+ sheetOpen ? /* @__PURE__ */ jsx2(BottomSheet, { open: true, onOpenChange: setSheetOpen, "aria-label": "Session actions", children: /* @__PURE__ */ jsx2("div", { className: "flex flex-col gap-1 p-2 *:w-full", role: "menu", children: /* @__PURE__ */ jsx2(PermissionGuard, { allowed: !disabled, children: /* @__PURE__ */ jsxs2(
243
+ ThreadListItemPrimitive.Delete,
244
+ {
245
+ className: deleteItemClass,
246
+ onClick: () => {
247
+ if (!disabled) setSheetOpen(false);
248
+ },
249
+ children: [
250
+ /* @__PURE__ */ jsx2(Icon, { name: "trash", className: "size-3.5" }),
251
+ "Delete"
252
+ ]
253
+ }
254
+ ) }) }) }) : null
255
+ ] });
256
+ }
257
+ return /* @__PURE__ */ jsxs2(ThreadListItemMorePrimitive.Root, { sharedFocusGroup: true, children: [
258
+ /* @__PURE__ */ jsx2(
259
+ ThreadListItemMorePrimitive.Trigger,
260
+ {
261
+ ref: setTriggerElement,
262
+ "aria-label": "Session actions",
263
+ title: "Session actions",
264
+ className: moreButtonClass,
265
+ children: /* @__PURE__ */ jsx2(Icon, { name: "ellipsis", className: "size-3.5" })
266
+ }
267
+ ),
268
+ /* @__PURE__ */ jsx2(
269
+ ThreadListItemMorePrimitive.Content,
270
+ {
271
+ portalProps: { container: portalContainer },
272
+ align: "end",
273
+ sideOffset: 4,
274
+ className: "font-sans-flex z-50 min-w-[8rem] rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md *:w-full",
275
+ children: /* @__PURE__ */ jsx2(PermissionGuard, { allowed: !disabled, children: /* @__PURE__ */ jsxs2(ThreadListItemPrimitive.Delete, { className: deleteItemClass, children: [
276
+ /* @__PURE__ */ jsx2(Icon, { name: "trash", className: "size-3.5" }),
277
+ "Delete"
278
+ ] }) })
279
+ }
280
+ )
281
+ ] });
282
+ }
283
+ function ThreadListItemRow({
284
+ onThreadOpen,
285
+ canDeleteSession,
286
+ canDeleteResource
287
+ }) {
288
+ const aui = useAui();
289
+ const shell = useOptionalShellMode();
290
+ const ThreadListRow = useSlot("ThreadListRow");
291
+ const id = useAuiState((s) => s.threadListItem.id);
292
+ const remoteId = useAuiState((s) => s.threadListItem.remoteId);
293
+ const title = useAuiState((s) => s.threadListItem.title);
294
+ const lastMessageAt = useAuiState((s) => s.threadListItem.lastMessageAt);
295
+ const custom = useAuiState((s) => s.threadListItem.custom);
296
+ const mainThreadId = useAuiState((s) => s.threads.mainThreadId);
297
+ const agentName = readThreadAgentName(custom);
298
+ const showDelete = canDeleteSession && remoteId != null;
299
+ const deleteDisabled = remoteId != null && !canDeleteResource(remoteId);
300
+ const sidebarNavOpen = shell?.libraryOpen === true || shell?.sessionsOpen === true || shell?.schedulesOpen === true;
301
+ return /* @__PURE__ */ jsx2(ThreadListItemPrimitive.Root, { className: "min-w-0", children: /* @__PURE__ */ jsx2(
302
+ ThreadListRow,
303
+ {
304
+ title: title ?? "New Chat",
305
+ active: id === mainThreadId && !sidebarNavOpen,
306
+ agentName,
307
+ lastMessageAt,
308
+ onSelect: () => {
309
+ onThreadOpen?.();
310
+ shell?.setSettingsOpen(false);
311
+ shell?.setLibraryOpen(false);
312
+ shell?.setSessionsOpen(false);
313
+ shell?.setSchedulesOpen(false);
314
+ const sessionMutable = threadListItemIsMutable(custom);
315
+ const sameImmutable = !sessionMutable && shell?.mode.status === "active" && !shell.mode.isMutable && (agentName == null ? shell.mode.agentName == null && shell.mode.agentId == null : shell.mode.agentName === agentName || shell.mode.agentId === agentName);
316
+ const sameMutable = canReuseMutableShell({
317
+ sessionMutable,
318
+ shellMutable: shell?.mode.status === "active" && shell.mode.isMutable,
319
+ ...shell?.mode.status === "active" && shell.mode.isMutable ? { shellAgentName: shell.mode.agentName, shellAgentId: shell.mode.agentId } : {},
320
+ remoteId,
321
+ pendingSessionId: shell?.pendingSessionId
322
+ });
323
+ if ((sameImmutable || sameMutable) && remoteId != null) {
324
+ void Promise.resolve(aui.threads().switchToThread(id)).catch(() => void 0);
325
+ return;
326
+ }
327
+ if (remoteId != null) {
328
+ shell?.openHistorySession({
329
+ sessionId: remoteId,
330
+ isMutable: sessionMutable,
331
+ ...agentName != null ? { agentName } : {}
332
+ });
333
+ return;
334
+ }
335
+ void Promise.resolve(aui.threads().switchToThread(id)).catch(() => void 0);
336
+ },
337
+ actions: showDelete ? /* @__PURE__ */ jsx2(ThreadListItemDeleteMenu, { disabled: deleteDisabled }) : void 0
338
+ }
339
+ ) });
340
+ }
341
+ function useThreadListIndicesByRecency(variant) {
342
+ const threadIds = useAuiState((s) => s.threads.threadIds);
343
+ const threadItems = useAuiState((s) => s.threads.threadItems);
344
+ return useMemo(() => {
345
+ const indices = threadListIndicesByRecency({ threadIds, threadItems });
346
+ if (variant === "default") return indices;
347
+ const itemById = /* @__PURE__ */ new Map();
348
+ for (const item of threadItems) {
349
+ itemById.set(item.id, item);
350
+ if (item.remoteId != null) itemById.set(item.remoteId, item);
351
+ }
352
+ return indices.filter((index) => {
353
+ const id = threadIds[index];
354
+ if (id === void 0) return false;
355
+ const item = itemById.get(id);
356
+ return item?.remoteId != null;
357
+ });
358
+ }, [threadIds, threadItems, variant]);
359
+ }
360
+ function ThreadListItemsByRecency({
361
+ indices,
362
+ onThreadOpen,
363
+ canDeleteSession,
364
+ canDeleteResource
365
+ }) {
366
+ const threadIds = useAuiState((s) => s.threads.threadIds);
367
+ return /* @__PURE__ */ jsx2(Fragment2, { children: indices.map((index) => {
368
+ const key = threadIds[index] ?? String(index);
369
+ return /* @__PURE__ */ jsx2(ThreadListItemByIndexProvider, { index, archived: false, children: /* @__PURE__ */ jsx2(
370
+ ThreadListItemRow,
371
+ {
372
+ onThreadOpen,
373
+ canDeleteSession,
374
+ canDeleteResource
375
+ }
376
+ ) }, key);
377
+ }) });
378
+ }
379
+ var THREAD_LIST_VIEWPORT_SLOT = "aui_thread-list-viewport";
380
+ var LOAD_MORE_BOTTOM_PX = 80;
381
+ function RecentChatsSection({
382
+ children,
383
+ viewportRef,
384
+ hideScrollbar
385
+ }) {
386
+ const shell = useOptionalShellMode();
387
+ const activeRemoteId = useAuiState((s) => s.threadListItem.remoteId);
388
+ const historyFilterIntent = shell?.historyAgentFilter?.intent;
389
+ const showFilter = shell?.isLibraryEnabled === true && historyFilterIntent !== "try-agent" && (historyFilterIntent === "history" || shell.mode.status !== "active" || shell.mode.isMutable || shell.pendingSessionId != null || activeRemoteId != null);
390
+ const heading = shell?.historyAgentFilter == null ? "Chat History" : `Chats for ${shell.historyAgentFilter.agentName}`;
391
+ return /* @__PURE__ */ jsxs2("div", { className: "flex min-h-0 flex-1 flex-col", children: [
392
+ /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-1 px-1 py-1", children: [
393
+ /* @__PURE__ */ jsx2("h2", { className: "min-w-0 flex-1 truncate px-1.5 py-1 text-sm font-medium text-text-secondary", children: heading }),
394
+ showFilter ? /* @__PURE__ */ jsx2(AgentHistoryFilterButton, {}) : null
395
+ ] }),
396
+ /* @__PURE__ */ jsx2(
397
+ "div",
398
+ {
399
+ ref: viewportRef,
400
+ "data-slot": THREAD_LIST_VIEWPORT_SLOT,
401
+ className: cn("flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto", hideScrollbar && "aui-scrollbar-hidden"),
402
+ children
403
+ }
404
+ )
405
+ ] });
406
+ }
407
+ function ThreadListContainer({ onThreadOpen, variant = "default" } = {}) {
408
+ const aui = useAui();
409
+ const server = useOptionalServer();
410
+ const isLoading = useAuiState((s) => s.threads.isLoading);
411
+ const isLoadingMore = useAuiState((s) => s.threads.isLoadingMore);
412
+ const hasMore = useAuiState((s) => s.threads.hasMore);
413
+ const threadIds = useAuiState((s) => s.threads.threadIds);
414
+ const threadItems = useAuiState((s) => s.threads.threadItems);
415
+ const shell = useOptionalShellMode();
416
+ const ThreadListShell = useSlot("ThreadListShell");
417
+ const ThreadListNewButton = useSlot("ThreadListNewButton");
418
+ const AgentsLibraryButton = useSlot("AgentsLibraryButton");
419
+ const SessionsBrowserButton = useSlot("SessionsBrowserButton");
420
+ const SchedulesButton = useSlot("SchedulesButton");
421
+ const ThreadListRowSkeleton = useSlot("ThreadListRowSkeleton");
422
+ const ThreadListEmptyState = useSlot("ThreadListEmptyState");
423
+ const indices = useThreadListIndicesByRecency(variant);
424
+ const viewportRef = useRef2(null);
425
+ const hasMoreRef = useRef2(hasMore);
426
+ const auiRef = useRef2(aui);
427
+ hasMoreRef.current = hasMore;
428
+ auiRef.current = aui;
429
+ const showNewChat = shell?.isNewChatEnabled !== false;
430
+ const isIdle = shell?.mode.status === "idle";
431
+ const isRecentHistory = variant === "recent-history";
432
+ const canDeleteSession = typeof server?.deleteSession === "function";
433
+ const remoteSessionIds = useMemo(
434
+ () => threadItems.flatMap((item) => item.remoteId == null ? [] : [item.remoteId]),
435
+ [threadItems]
436
+ );
437
+ const { allows } = useResourcePermissions({ resourceType: "session", resourceIds: remoteSessionIds });
438
+ useEffect2(() => {
439
+ if (isIdle || isLoading || isLoadingMore) return;
440
+ const viewport = viewportRef.current;
441
+ if (!viewport) return;
442
+ let cancelled = false;
443
+ const tryLoadMore = () => {
444
+ if (cancelled || !hasMoreRef.current) return;
445
+ if (viewport.clientHeight <= 0) return;
446
+ const remaining = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
447
+ if (viewport.scrollHeight > viewport.clientHeight && remaining > LOAD_MORE_BOTTOM_PX) return;
448
+ void auiRef.current.threads().loadMore();
449
+ };
450
+ viewport.addEventListener("scroll", tryLoadMore, { passive: true });
451
+ const resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(() => tryLoadMore());
452
+ if (resizeObserver) {
453
+ resizeObserver.observe(viewport);
454
+ } else {
455
+ window.addEventListener("resize", tryLoadMore);
456
+ }
457
+ tryLoadMore();
458
+ return () => {
459
+ cancelled = true;
460
+ viewport.removeEventListener("scroll", tryLoadMore);
461
+ resizeObserver?.disconnect();
462
+ if (!resizeObserver) {
463
+ window.removeEventListener("resize", tryLoadMore);
464
+ }
465
+ };
466
+ }, [hasMore, isIdle, isLoading, isLoadingMore, threadIds.length]);
467
+ const handleNewChat = () => {
468
+ onThreadOpen?.();
469
+ shell?.setLibraryOpen(false);
470
+ shell?.setSessionsOpen(false);
471
+ if (shell?.isComposerEnabled) {
472
+ shell.openDraft();
473
+ return;
474
+ }
475
+ shell?.setSettingsOpen(false);
476
+ shell?.setSchedulesOpen(false);
477
+ void Promise.resolve(aui.threads().switchToNewThread()).catch(() => void 0);
478
+ };
479
+ let listBody;
480
+ if (isIdle) {
481
+ listBody = /* @__PURE__ */ jsx2(ThreadListEmptyState, { message: isRecentHistory ? "No recent chats" : void 0 });
482
+ } else if (isLoading) {
483
+ listBody = /* @__PURE__ */ jsx2(ThreadListRowSkeleton, {});
484
+ } else if (indices.length === 0) {
485
+ listBody = /* @__PURE__ */ jsx2(ThreadListEmptyState, { message: isRecentHistory ? "No recent chats" : void 0 });
486
+ } else {
487
+ listBody = /* @__PURE__ */ jsx2(ThreadListPrimitive.Root, { className: "flex min-h-0 flex-col gap-0.5", children: /* @__PURE__ */ jsx2(
488
+ ThreadListItemsByRecency,
489
+ {
490
+ indices,
491
+ onThreadOpen,
492
+ canDeleteSession,
493
+ canDeleteResource: (sessionId) => allows(sessionId, "DELETE")
494
+ }
495
+ ) });
496
+ }
497
+ return /* @__PURE__ */ jsx2(
498
+ ThreadListShell,
499
+ {
500
+ header: isRecentHistory ? null : /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1", children: [
501
+ showNewChat ? /* @__PURE__ */ jsx2(ThreadListNewButton, { onClick: handleNewChat }) : null,
502
+ /* @__PURE__ */ jsx2(AgentsLibraryButton, {}),
503
+ /* @__PURE__ */ jsx2(SessionsBrowserButton, {}),
504
+ /* @__PURE__ */ jsx2(SchedulesButton, {})
505
+ ] }),
506
+ children: /* @__PURE__ */ jsxs2(RecentChatsSection, { viewportRef, hideScrollbar: isRecentHistory, children: [
507
+ listBody,
508
+ !isIdle && hasMore ? /* @__PURE__ */ jsx2("div", { className: "h-4 shrink-0", "aria-hidden": true }) : null
509
+ ] })
510
+ }
511
+ );
512
+ }
513
+
514
+ export {
515
+ ThreadListContainer
516
+ };
517
+ //# sourceMappingURL=chunk-XO3FYN2W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/containers/ThreadListContainer.tsx","../src/atoms/AgentHistoryFilterButton.tsx"],"sourcesContent":["'use client';\n\nimport {\n ThreadListItemByIndexProvider,\n ThreadListItemMorePrimitive,\n ThreadListItemPrimitive,\n ThreadListPrimitive,\n useAui,\n useAuiState,\n} from '@assistant-ui/react';\nimport { useCallback, useEffect, useMemo, useRef, useState, type ReactNode, type Ref } from 'react';\n\nimport { AgentHistoryFilterButton } from '../atoms/AgentHistoryFilterButton.js';\nimport { auiButtonClass } from '../atoms/lib/buttonClasses.js';\nimport { cn } from '../atoms/lib/cn.js';\nimport { useCompactLayout } from '../atoms/lib/CompactLayoutContext.js';\nimport {\n canReuseMutableShell,\n readThreadAgentName,\n threadListIndicesByRecency,\n threadListItemIsMutable,\n} from '../atoms/lib/threadListMeta.js';\nimport { useIsMobile } from '../atoms/lib/useIsMobile.js';\nimport { BottomSheet } from '../atoms/primitives/BottomSheet.js';\nimport { useResourcePermissions } from '../hooks/useResourcePermissions.js';\nimport { Icon } from '../icons/Icon.js';\nimport { useOptionalServer } from '../server/ServerContext.js';\nimport { useOptionalShellMode } from '../server/ShellModeContext.js';\nimport { useSlot } from '../theme/SlotsProvider.js';\n\n/**\n * Simplified relative to the reference: renders threads in a single flat list\n * rather than grouping them by Today/Yesterday/Earlier.\n *\n * Delete uses assistant-ui ThreadListItemPrimitive.Delete / ThreadListItemMorePrimitive\n * (adapter.delete → server.deleteSession). Mobile/compact keeps a BottomSheet chrome.\n */\nexport type ThreadListContainerProps = {\n /** Called after New chat or selecting a row — used by stack/drawer chrome. */\n onThreadOpen?: () => void;\n /** `recent-history` hides navigation and lists only persisted sessions. */\n variant?: 'default' | 'recent-history';\n};\n\nconst deleteItemClass =\n 'flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-failure-bg outline-none transition-colors hover:bg-failure-bg/12 hover:text-failure-bg focus:bg-failure-bg/12 focus:text-failure-bg data-[highlighted]:bg-failure-bg/12 data-[highlighted]:text-failure-bg';\n\nfunction ThreadListItemDeleteMenu({ disabled }: { disabled: boolean }) {\n const PermissionGuard = useSlot('PermissionGuard');\n const compact = useCompactLayout();\n const isMobile = useIsMobile();\n const [sheetOpen, setSheetOpen] = useState(false);\n const [portalContainer, setPortalContainer] = useState<HTMLElement>();\n const useSheet = isMobile || compact;\n const setTriggerElement = useCallback((element: HTMLButtonElement | null) => {\n const themeRoot = element?.closest('.aui-theme-root');\n setPortalContainer(themeRoot instanceof HTMLElement ? themeRoot : undefined);\n }, []);\n\n const moreButtonClass = auiButtonClass({\n variant: 'ghost',\n size: 'icon',\n className: 'size-7 shrink-0 text-text-secondary hover:bg-transparent hover:text-text-primary',\n });\n\n if (useSheet) {\n return (\n <>\n <button\n type=\"button\"\n aria-label=\"Session actions\"\n title=\"Session actions\"\n aria-haspopup=\"dialog\"\n aria-expanded={sheetOpen}\n className={moreButtonClass}\n onClick={() => setSheetOpen(true)}\n >\n <Icon name=\"ellipsis\" className=\"size-3.5\" />\n </button>\n {sheetOpen ? (\n <BottomSheet open onOpenChange={setSheetOpen} aria-label=\"Session actions\">\n <div className=\"flex flex-col gap-1 p-2 *:w-full\" role=\"menu\">\n <PermissionGuard allowed={!disabled}>\n <ThreadListItemPrimitive.Delete\n className={deleteItemClass}\n onClick={() => {\n if (!disabled) setSheetOpen(false);\n }}\n >\n <Icon name=\"trash\" className=\"size-3.5\" />\n Delete\n </ThreadListItemPrimitive.Delete>\n </PermissionGuard>\n </div>\n </BottomSheet>\n ) : null}\n </>\n );\n }\n\n return (\n <ThreadListItemMorePrimitive.Root sharedFocusGroup>\n <ThreadListItemMorePrimitive.Trigger\n ref={setTriggerElement}\n aria-label=\"Session actions\"\n title=\"Session actions\"\n className={moreButtonClass}\n >\n <Icon name=\"ellipsis\" className=\"size-3.5\" />\n </ThreadListItemMorePrimitive.Trigger>\n <ThreadListItemMorePrimitive.Content\n portalProps={{ container: portalContainer }}\n align=\"end\"\n sideOffset={4}\n className=\"font-sans-flex z-50 min-w-[8rem] rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md *:w-full\"\n >\n <PermissionGuard allowed={!disabled}>\n <ThreadListItemPrimitive.Delete className={deleteItemClass}>\n <Icon name=\"trash\" className=\"size-3.5\" />\n Delete\n </ThreadListItemPrimitive.Delete>\n </PermissionGuard>\n </ThreadListItemMorePrimitive.Content>\n </ThreadListItemMorePrimitive.Root>\n );\n}\n\nfunction ThreadListItemRow({\n onThreadOpen,\n canDeleteSession,\n canDeleteResource,\n}: {\n onThreadOpen?: () => void;\n canDeleteSession: boolean;\n canDeleteResource: (sessionId: string) => boolean;\n}) {\n const aui = useAui();\n const shell = useOptionalShellMode();\n const ThreadListRow = useSlot('ThreadListRow');\n const id = useAuiState(s => s.threadListItem.id);\n const remoteId = useAuiState(s => s.threadListItem.remoteId);\n const title = useAuiState(s => s.threadListItem.title);\n const lastMessageAt = useAuiState(s => s.threadListItem.lastMessageAt);\n const custom = useAuiState(s => s.threadListItem.custom);\n const mainThreadId = useAuiState(s => s.threads.mainThreadId);\n const agentName = readThreadAgentName(custom);\n const showDelete = canDeleteSession && remoteId != null;\n const deleteDisabled = remoteId != null && !canDeleteResource(remoteId);\n const sidebarNavOpen = shell?.libraryOpen === true || shell?.sessionsOpen === true || shell?.schedulesOpen === true;\n\n return (\n <ThreadListItemPrimitive.Root className=\"min-w-0\">\n <ThreadListRow\n title={title ?? 'New Chat'}\n active={id === mainThreadId && !sidebarNavOpen}\n agentName={agentName}\n lastMessageAt={lastMessageAt}\n onSelect={() => {\n onThreadOpen?.();\n shell?.setSettingsOpen(false);\n shell?.setLibraryOpen(false);\n shell?.setSessionsOpen(false);\n shell?.setSchedulesOpen(false);\n\n // Prefer custom.isMutable (session wire); agentName-only is a legacy fallback.\n const sessionMutable = threadListItemIsMutable(custom);\n const sameImmutable =\n !sessionMutable &&\n shell?.mode.status === 'active' &&\n !shell.mode.isMutable &&\n (agentName == null\n ? shell.mode.agentName == null && shell.mode.agentId == null\n : shell.mode.agentName === agentName || shell.mode.agentId === agentName);\n const sameMutable = canReuseMutableShell({\n sessionMutable,\n shellMutable: shell?.mode.status === 'active' && shell.mode.isMutable,\n ...(shell?.mode.status === 'active' && shell.mode.isMutable\n ? { shellAgentName: shell.mode.agentName, shellAgentId: shell.mode.agentId }\n : {}),\n remoteId,\n pendingSessionId: shell?.pendingSessionId,\n });\n\n if ((sameImmutable || sameMutable) && remoteId != null) {\n void Promise.resolve(aui.threads().switchToThread(id)).catch(() => undefined);\n return;\n }\n if (remoteId != null) {\n shell?.openHistorySession({\n sessionId: remoteId,\n isMutable: sessionMutable,\n ...(agentName != null ? { agentName } : {}),\n });\n return;\n }\n void Promise.resolve(aui.threads().switchToThread(id)).catch(() => undefined);\n }}\n actions={showDelete ? <ThreadListItemDeleteMenu disabled={deleteDisabled} /> : undefined}\n />\n </ThreadListItemPrimitive.Root>\n );\n}\n\nfunction useThreadListIndicesByRecency(variant: NonNullable<ThreadListContainerProps['variant']>): number[] {\n const threadIds = useAuiState(s => s.threads.threadIds);\n const threadItems = useAuiState(s => s.threads.threadItems);\n\n return useMemo(() => {\n const indices = threadListIndicesByRecency({ threadIds, threadItems });\n if (variant === 'default') return indices;\n\n const itemById = new Map<string, (typeof threadItems)[number]>();\n for (const item of threadItems) {\n itemById.set(item.id, item);\n if (item.remoteId != null) itemById.set(item.remoteId, item);\n }\n\n return indices.filter(index => {\n const id = threadIds[index];\n if (id === undefined) return false;\n const item = itemById.get(id);\n return item?.remoteId != null;\n });\n }, [threadIds, threadItems, variant]);\n}\n\nfunction ThreadListItemsByRecency({\n indices,\n onThreadOpen,\n canDeleteSession,\n canDeleteResource,\n}: {\n indices: number[];\n onThreadOpen?: () => void;\n canDeleteSession: boolean;\n canDeleteResource: (sessionId: string) => boolean;\n}) {\n // Newest-first: remount/switchToThread can append the active session to threadIds.\n const threadIds = useAuiState(s => s.threads.threadIds);\n\n return (\n <>\n {indices.map(index => {\n const key = threadIds[index] ?? String(index);\n return (\n <ThreadListItemByIndexProvider key={key} index={index} archived={false}>\n <ThreadListItemRow\n onThreadOpen={onThreadOpen}\n canDeleteSession={canDeleteSession}\n canDeleteResource={canDeleteResource}\n />\n </ThreadListItemByIndexProvider>\n );\n })}\n </>\n );\n}\n\nconst THREAD_LIST_VIEWPORT_SLOT = 'aui_thread-list-viewport';\n/** How close to the bottom (px) before the next sessions page is fetched. */\nconst LOAD_MORE_BOTTOM_PX = 80;\n\nfunction RecentChatsSection({\n children,\n viewportRef,\n hideScrollbar,\n}: {\n children: ReactNode;\n viewportRef: Ref<HTMLDivElement>;\n hideScrollbar: boolean;\n}) {\n const shell = useOptionalShellMode();\n const activeRemoteId = useAuiState(s => s.threadListItem.remoteId);\n const historyFilterIntent = shell?.historyAgentFilter?.intent;\n const showFilter =\n shell?.isLibraryEnabled === true &&\n historyFilterIntent !== 'try-agent' &&\n (historyFilterIntent === 'history' ||\n shell.mode.status !== 'active' ||\n shell.mode.isMutable ||\n shell.pendingSessionId != null ||\n activeRemoteId != null);\n const heading =\n shell?.historyAgentFilter == null ? 'Chat History' : `Chats for ${shell.historyAgentFilter.agentName}`;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div className=\"flex shrink-0 items-center gap-1 px-1 py-1\">\n <h2 className=\"min-w-0 flex-1 truncate px-1.5 py-1 text-sm font-medium text-text-secondary\">{heading}</h2>\n {showFilter ? <AgentHistoryFilterButton /> : null}\n </div>\n <div\n ref={viewportRef}\n data-slot={THREAD_LIST_VIEWPORT_SLOT}\n className={cn('flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto', hideScrollbar && 'aui-scrollbar-hidden')}\n >\n {children}\n </div>\n </div>\n );\n}\n\nexport function ThreadListContainer({ onThreadOpen, variant = 'default' }: ThreadListContainerProps = {}) {\n const aui = useAui();\n const server = useOptionalServer();\n const isLoading = useAuiState(s => s.threads.isLoading);\n const isLoadingMore = useAuiState(s => s.threads.isLoadingMore);\n const hasMore = useAuiState(s => s.threads.hasMore);\n const threadIds = useAuiState(s => s.threads.threadIds);\n const threadItems = useAuiState(s => s.threads.threadItems);\n const shell = useOptionalShellMode();\n\n const ThreadListShell = useSlot('ThreadListShell');\n const ThreadListNewButton = useSlot('ThreadListNewButton');\n const AgentsLibraryButton = useSlot('AgentsLibraryButton');\n const SessionsBrowserButton = useSlot('SessionsBrowserButton');\n const SchedulesButton = useSlot('SchedulesButton');\n const ThreadListRowSkeleton = useSlot('ThreadListRowSkeleton');\n const ThreadListEmptyState = useSlot('ThreadListEmptyState');\n\n const indices = useThreadListIndicesByRecency(variant);\n const viewportRef = useRef<HTMLDivElement>(null);\n const hasMoreRef = useRef(hasMore);\n const auiRef = useRef(aui);\n hasMoreRef.current = hasMore;\n auiRef.current = aui;\n\n const showNewChat = shell?.isNewChatEnabled !== false;\n const isIdle = shell?.mode.status === 'idle';\n const isRecentHistory = variant === 'recent-history';\n const canDeleteSession = typeof server?.deleteSession === 'function';\n const remoteSessionIds = useMemo(\n () => threadItems.flatMap(item => (item.remoteId == null ? [] : [item.remoteId])),\n [threadItems],\n );\n const { allows } = useResourcePermissions({ resourceType: 'session', resourceIds: remoteSessionIds });\n\n // Fill an underflowing viewport; once it scrolls, paginate only near the bottom.\n // Re-measure after commit (threadIds / hasMore) instead of rAF-chaining, which\n // raced layout and could drain every remaining listSessions page.\n // The runtime owns request deduplication, so Strict Mode remounts can recheck safely.\n useEffect(() => {\n if (isIdle || isLoading || isLoadingMore) return;\n const viewport = viewportRef.current;\n if (!viewport) return;\n\n let cancelled = false;\n\n const tryLoadMore = () => {\n if (cancelled || !hasMoreRef.current) return;\n if (viewport.clientHeight <= 0) return;\n\n const remaining = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;\n if (viewport.scrollHeight > viewport.clientHeight && remaining > LOAD_MORE_BOTTOM_PX) return;\n\n void auiRef.current.threads().loadMore();\n };\n\n viewport.addEventListener('scroll', tryLoadMore, { passive: true });\n const resizeObserver = typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(() => tryLoadMore());\n if (resizeObserver) {\n resizeObserver.observe(viewport);\n } else {\n window.addEventListener('resize', tryLoadMore);\n }\n tryLoadMore();\n\n return () => {\n cancelled = true;\n viewport.removeEventListener('scroll', tryLoadMore);\n resizeObserver?.disconnect();\n if (!resizeObserver) {\n window.removeEventListener('resize', tryLoadMore);\n }\n };\n }, [hasMore, isIdle, isLoading, isLoadingMore, threadIds.length]);\n\n const handleNewChat = () => {\n onThreadOpen?.();\n shell?.setLibraryOpen(false);\n shell?.setSessionsOpen(false);\n if (shell?.isComposerEnabled) {\n shell.openDraft();\n return;\n }\n shell?.setSettingsOpen(false);\n shell?.setSchedulesOpen(false);\n void Promise.resolve(aui.threads().switchToNewThread()).catch(() => undefined);\n };\n\n let listBody: ReactNode;\n if (isIdle) {\n listBody = <ThreadListEmptyState message={isRecentHistory ? 'No recent chats' : undefined} />;\n } else if (isLoading) {\n listBody = <ThreadListRowSkeleton />;\n } else if (indices.length === 0) {\n listBody = <ThreadListEmptyState message={isRecentHistory ? 'No recent chats' : undefined} />;\n } else {\n listBody = (\n <ThreadListPrimitive.Root className=\"flex min-h-0 flex-col gap-0.5\">\n <ThreadListItemsByRecency\n indices={indices}\n onThreadOpen={onThreadOpen}\n canDeleteSession={canDeleteSession}\n canDeleteResource={sessionId => allows(sessionId, 'DELETE')}\n />\n </ThreadListPrimitive.Root>\n );\n }\n\n return (\n <ThreadListShell\n header={\n isRecentHistory ? null : (\n <div className=\"flex flex-col gap-1\">\n {showNewChat ? <ThreadListNewButton onClick={handleNewChat} /> : null}\n <AgentsLibraryButton />\n <SessionsBrowserButton />\n <SchedulesButton />\n </div>\n )\n }\n >\n <RecentChatsSection viewportRef={viewportRef} hideScrollbar={isRecentHistory}>\n {listBody}\n {!isIdle && hasMore ? <div className=\"h-4 shrink-0\" aria-hidden /> : null}\n </RecentChatsSection>\n </ThreadListShell>\n );\n}\n","'use client';\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { Icon } from '../icons/Icon.js';\nimport { useOptionalServer } from '../server/ServerContext.js';\nimport { libraryAgentId, useOptionalShellMode, type HistoryAgentFilter } from '../server/ShellModeContext.js';\nimport { auiButtonClass } from './lib/buttonClasses.js';\nimport { cn } from './lib/cn.js';\nimport { useCompactLayout } from './lib/CompactLayoutContext.js';\nimport { themePortalRoot } from './lib/themePortalRoot.js';\nimport { useIsMobile } from './lib/useIsMobile.js';\nimport { useSearchAgentsList } from './lib/useSearchAgentsList.js';\nimport { BottomSheet } from './primitives/BottomSheet.js';\nimport { DropdownMenuItem } from './primitives/DropdownMenu.js';\nimport SearchInput from './primitives/SearchInput.js';\n\n/**\n * Funnel popover for filtering chat history by agent id.\n * Desktop: fixed menu to the right of the funnel. Mobile/compact: bottom sheet.\n */\nexport function AgentHistoryFilterButton() {\n const shell = useOptionalShellMode();\n const server = useOptionalServer();\n const isMobile = useIsMobile();\n const compact = useCompactLayout();\n const useSheet = isMobile || compact;\n\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState('');\n const [menuPos, setMenuPos] = useState<{ top: number; left: number } | null>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const menuId = useId();\n\n const enabled = shell?.isLibraryEnabled === true && server != null;\n const selected = shell?.historyAgentFilter ?? null;\n\n useEffect(() => {\n if (!open) setQuery('');\n }, [open]);\n\n const { agents, isInitialLoading, isSearching, loadingMore, hasMore, listRef, sentinelRef } = useSearchAgentsList({\n enabled: open && enabled,\n query,\n });\n\n // Desktop only: anchor to the right of the funnel; portal escapes sidebar overflow.\n useLayoutEffect(() => {\n if (!open || useSheet) {\n setMenuPos(null);\n return;\n }\n const update = () => {\n const rect = buttonRef.current?.getBoundingClientRect();\n if (!rect) return;\n setMenuPos({ top: rect.top, left: rect.right + 4 });\n };\n update();\n window.addEventListener('resize', update);\n window.addEventListener('scroll', update, true);\n return () => {\n window.removeEventListener('resize', update);\n window.removeEventListener('scroll', update, true);\n };\n }, [open, useSheet]);\n\n useEffect(() => {\n if (!open || useSheet) return;\n const handler = (e: MouseEvent) => {\n const target = e.target as Node;\n if (buttonRef.current?.contains(target) || menuRef.current?.contains(target)) return;\n setOpen(false);\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [open, useSheet]);\n\n if (!enabled) return null;\n\n // Reset the active session so the newly scoped history starts from a clean runtime and first page.\n const pick = (filter: HistoryAgentFilter | null) => {\n if (shell?.isComposerEnabled === true) {\n shell.openDraft();\n } else {\n shell?.openLibraryHome();\n }\n shell?.setHistoryAgentFilter(filter);\n setOpen(false);\n };\n\n const filterBody = (\n <>\n <div className=\"p-1\" onMouseDown={e => e.stopPropagation()}>\n <SearchInput query={query} setQuery={setQuery} placeholder=\"Search agents\" />\n {isSearching ? (\n <p className=\"text-text-secondary px-1 pt-1 text-[11px]\" role=\"status\">\n Searching…\n </p>\n ) : null}\n </div>\n <div\n ref={listRef}\n className={cn('mt-1 overflow-y-auto', useSheet ? 'min-h-0 flex-1 px-1 pb-2' : 'min-h-48 max-h-64')}\n >\n {query.trim() === '' ? (\n <DropdownMenuItem\n className={cn(\n 'justify-between',\n selected == null && 'bg-dropdown-selected-item-bg text-dropdown-selected-item-text',\n )}\n onClick={() => pick(null)}\n >\n All chats\n {selected == null ? <Icon name=\"check\" className=\"size-3.5 shrink-0\" /> : null}\n </DropdownMenuItem>\n ) : null}\n {isInitialLoading ? (\n <p className=\"px-2 py-3 text-center text-xs text-text-secondary\">Loading…</p>\n ) : agents.length === 0 ? (\n <p className=\"text-text-secondary px-2 py-6 text-center text-xs\" role=\"status\">\n {query.trim() ? `No agents match \"${query.trim()}\".` : 'No agents yet.'}\n </p>\n ) : (\n <>\n {agents.map(agent => {\n const id = libraryAgentId(agent);\n const active = selected?.agentId === id;\n return (\n <DropdownMenuItem\n key={id}\n className={cn(\n 'justify-between gap-2 text-left',\n active && 'bg-dropdown-selected-item-bg text-dropdown-selected-item-text',\n )}\n onClick={() => pick({ agentId: id, agentName: agent.name, intent: 'history' })}\n >\n <span className=\"min-w-0 truncate\">{agent.name}</span>\n {active ? <Icon name=\"check\" className=\"size-3.5 shrink-0\" /> : null}\n </DropdownMenuItem>\n );\n })}\n {hasMore ? (\n <div ref={sentinelRef} className=\"flex h-6 shrink-0 items-center justify-center\" aria-hidden>\n {loadingMore ? (\n <span className=\"text-text-secondary text-[11px]\" role=\"status\">\n Loading more…\n </span>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n </div>\n </>\n );\n\n return (\n <div className=\"relative shrink-0\">\n <button\n ref={buttonRef}\n type=\"button\"\n aria-label={\n selected != null ? `Filter chat history by agent (${selected.agentName})` : 'Filter chat history by agent'\n }\n aria-haspopup={useSheet ? 'dialog' : 'menu'}\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n title=\"Filter by agent\"\n className={auiButtonClass({\n variant: 'ghost',\n size: 'icon',\n className: cn(\n 'relative size-7 shrink-0 text-text-secondary hover:bg-ghost-button-hover hover:text-ghost-button-text',\n selected != null && 'text-text-primary',\n ),\n })}\n onClick={() => setOpen(v => !v)}\n >\n <Icon name=\"funnel\" className=\"size-3.5\" />\n {selected != null ? (\n <span\n className=\"bg-primary-button-bg absolute top-1 right-1 size-1.5 rounded-full\"\n aria-hidden\n data-testid=\"history-filter-active-dot\"\n />\n ) : null}\n </button>\n {useSheet && open ? (\n <BottomSheet open onOpenChange={setOpen} id={menuId} aria-label=\"Filter agents\">\n <div className=\"flex min-h-0 flex-1 flex-col p-2\" role=\"menu\">\n {filterBody}\n </div>\n </BottomSheet>\n ) : null}\n {!useSheet && open && menuPos != null\n ? createPortal(\n <div\n ref={menuRef}\n id={menuId}\n role=\"menu\"\n aria-label=\"Filter agents\"\n style={{ top: menuPos.top, left: menuPos.left }}\n className=\"font-sans-flex fixed z-50 w-56 rounded-md border border-border bg-card-bg p-1 text-text-primary shadow-md\"\n >\n {filterBody}\n </div>,\n themePortalRoot(buttonRef.current),\n )\n : null}\n </div>\n );\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect"]}
@@ -1,13 +1,13 @@
1
- import { AgentSpec, ModelSelection, AgentSkill, ConnectorState, AgentLibraryEntry, SaveAgentResult, CatalogServer, AgentBuilderCapabilitiesResponse, AgentSessionsServer, AgentMetricsServer, ScheduleServer, AgentChatServer, PageParams, ListResult, AgentBuilderServer, SearchAgentsParams, SaveAgentRequest } from '@truefoundry/assistant-ui-runtime/server';
1
+ import { AgentSpec, ModelSelection, AgentSkill, ConnectorState, AgentLibraryEntry, SaveAgentResult, CatalogServer, AgentBuilderCapabilitiesResponse, AgentSessionsServer, AgentMetricsServer, ScheduleServer, PermissionsServer, AgentChatServer, AgentBuilderServer, SearchAgentsParams, SaveAgentRequest } from '@truefoundry/assistant-ui-runtime/server';
2
2
 
3
- type CreateTrueFoundryServerOptions<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelection = ModelSelection, TSkill extends AgentSkill = AgentSkill, TMcp extends ConnectorState = ConnectorState, TAgent extends AgentLibraryEntry = AgentLibraryEntry, TSave extends SaveAgentResult = SaveAgentResult, TCatalog extends CatalogServer = CatalogServer, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse, TSessions extends AgentSessionsServer<TSpec> = AgentSessionsServer<TSpec>, TMetrics extends AgentMetricsServer = AgentMetricsServer, TSchedules extends ScheduleServer = ScheduleServer> = {
3
+ type CreateTrueFoundryServerOptions<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelection = ModelSelection, TSkill extends AgentSkill = AgentSkill, TMcp extends ConnectorState = ConnectorState, TAgent extends AgentLibraryEntry = AgentLibraryEntry, TSave extends SaveAgentResult = SaveAgentResult, TCatalog extends CatalogServer = CatalogServer, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse, TSessions extends AgentSessionsServer<TSpec> = AgentSessionsServer<TSpec>, TMetrics extends AgentMetricsServer = AgentMetricsServer, TSchedules extends ScheduleServer = ScheduleServer, TPermissions extends PermissionsServer = PermissionsServer> = {
4
4
  /** Chat port — e.g. from `@truefoundry/agent-server-adapter`. */
5
5
  chatServer: AgentChatServer<TSpec>;
6
6
  getCapabilities: () => Promise<TCapabilities>;
7
7
  getModels: () => Promise<TModel[]>;
8
8
  getSkills: () => Promise<TSkill[]>;
9
9
  getMcp: () => Promise<TMcp[]>;
10
- listMcp?: (req?: PageParams) => Promise<ListResult<TMcp>>;
10
+ getMcpConnector?: AgentBuilderServer<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCapabilities>['getMcpConnector'];
11
11
  getMcpTools?: AgentBuilderServer<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCapabilities>['getMcpTools'];
12
12
  searchAgents: (req?: SearchAgentsParams) => Promise<TAgent[]>;
13
13
  saveAgent: (req: SaveAgentRequest<TSpec>) => Promise<TSave>;
@@ -22,18 +22,21 @@ type CreateTrueFoundryServerOptions<TSpec extends AgentSpec = AgentSpec, TModel
22
22
  metrics?: TMetrics;
23
23
  /** Schedules listing + CRUD. Optional. */
24
24
  schedules?: TSchedules;
25
+ /** Per-resource grants. Omit to leave actions enabled. */
26
+ permissions?: TPermissions;
25
27
  };
26
- type TrueFoundryServer<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelection = ModelSelection, TSkill extends AgentSkill = AgentSkill, TMcp extends ConnectorState = ConnectorState, TAgent extends AgentLibraryEntry = AgentLibraryEntry, TSave extends SaveAgentResult = SaveAgentResult, TCatalog extends CatalogServer = CatalogServer, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse, TSessions extends AgentSessionsServer<TSpec> = AgentSessionsServer<TSpec>, TMetrics extends AgentMetricsServer = AgentMetricsServer, TSchedules extends ScheduleServer = ScheduleServer> = AgentChatServer<TSpec> & AgentBuilderServer<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCapabilities> & {
28
+ type TrueFoundryServer<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelection = ModelSelection, TSkill extends AgentSkill = AgentSkill, TMcp extends ConnectorState = ConnectorState, TAgent extends AgentLibraryEntry = AgentLibraryEntry, TSave extends SaveAgentResult = SaveAgentResult, TCatalog extends CatalogServer = CatalogServer, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse, TSessions extends AgentSessionsServer<TSpec> = AgentSessionsServer<TSpec>, TMetrics extends AgentMetricsServer = AgentMetricsServer, TSchedules extends ScheduleServer = ScheduleServer, TPermissions extends PermissionsServer = PermissionsServer> = AgentChatServer<TSpec> & AgentBuilderServer<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCapabilities> & {
27
29
  catalog?: TCatalog;
28
30
  sessions?: TSessions;
29
31
  metrics?: TMetrics;
30
32
  schedules?: TSchedules;
33
+ permissions?: TPermissions;
31
34
  };
32
35
  /**
33
36
  * Composes an `AgentChatServer` with host-provided builder catalog callbacks
34
37
  * and an optional settings `catalog`.
35
38
  * Gateway wiring lives in the host (or `@truefoundry/agent-server-adapter`).
36
39
  */
37
- declare function createTrueFoundryServer<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelection = ModelSelection, TSkill extends AgentSkill = AgentSkill, TMcp extends ConnectorState = ConnectorState, TAgent extends AgentLibraryEntry = AgentLibraryEntry, TSave extends SaveAgentResult = SaveAgentResult, TCatalog extends CatalogServer = CatalogServer, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse, TSessions extends AgentSessionsServer<TSpec> = AgentSessionsServer<TSpec>, TMetrics extends AgentMetricsServer = AgentMetricsServer, TSchedules extends ScheduleServer = ScheduleServer>(opts: CreateTrueFoundryServerOptions<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCatalog, TCapabilities, TSessions, TMetrics, TSchedules>): TrueFoundryServer<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCatalog, TCapabilities, TSessions, TMetrics, TSchedules>;
40
+ declare function createTrueFoundryServer<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelection = ModelSelection, TSkill extends AgentSkill = AgentSkill, TMcp extends ConnectorState = ConnectorState, TAgent extends AgentLibraryEntry = AgentLibraryEntry, TSave extends SaveAgentResult = SaveAgentResult, TCatalog extends CatalogServer = CatalogServer, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse, TSessions extends AgentSessionsServer<TSpec> = AgentSessionsServer<TSpec>, TMetrics extends AgentMetricsServer = AgentMetricsServer, TSchedules extends ScheduleServer = ScheduleServer, TPermissions extends PermissionsServer = PermissionsServer>(opts: CreateTrueFoundryServerOptions<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCatalog, TCapabilities, TSessions, TMetrics, TSchedules, TPermissions>): TrueFoundryServer<TSpec, TModel, TSkill, TMcp, TAgent, TSave, TCatalog, TCapabilities, TSessions, TMetrics, TSchedules, TPermissions>;
38
41
 
39
42
  export { type CreateTrueFoundryServerOptions as C, type TrueFoundryServer as T, createTrueFoundryServer as c };