ai-design-system 0.1.54 → 0.1.56

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.
@@ -22,7 +22,7 @@ type ReasoningContextValue = {
22
22
 
23
23
  const ReasoningContext = createContext<ReasoningContextValue | null>(null);
24
24
 
25
- const useReasoning = () => {
25
+ export const useReasoning = () => {
26
26
  const context = useContext(ReasoningContext);
27
27
  if (!context) {
28
28
  throw new Error("Reasoning components must be used within Reasoning");
@@ -124,14 +124,14 @@ export const Reasoning = memo(
124
124
 
125
125
  export type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
126
126
 
127
- const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
128
- if (isStreaming || duration === 0) {
127
+ export const getThinkingMessage = (isStreaming: boolean, duration?: number) => {
128
+ if (isStreaming) {
129
129
  return <Shimmer duration={1}>Thinking...</Shimmer>;
130
130
  }
131
- if (duration === undefined) {
132
- return <p>Thought for a few seconds</p>;
131
+ if (duration === undefined || duration === 0) {
132
+ return <span>Thought for a few seconds</span>;
133
133
  }
134
- return <p>Thought for {duration} seconds</p>;
134
+ return <span>Thought for {duration} seconds</span>;
135
135
  };
136
136
 
137
137
  export const ReasoningTrigger = memo(
@@ -11,6 +11,7 @@ import { UserMessage } from "@/components/composites/UserMessage"
11
11
  import { SpecialistMessage } from "@/components/composites/SpecialistMessage"
12
12
  import { OrchestratorMessage } from "@/components/composites/OrchestratorMessage"
13
13
  import { ToolCallDisplay } from "@/components/composites/ToolCallDisplay"
14
+ import { ReasoningDisplay } from "@/components/composites/ReasoningDisplay"
14
15
  import { ApprovalCard } from "@/components/composites/ApprovalCard"
15
16
 
16
17
  /**
@@ -127,28 +128,49 @@ export const AIConversation = React.memo<AIConversationProps>(
127
128
 
128
129
  // Filter tool calls that aren't "task" type (those become sub-agents)
129
130
  // Also completely hide "ask_user" and "ask_question" tools so they are ONLY rendered in the prompt input area
130
- const directToolCalls =
131
+ const allToolCalls =
131
132
  message.toolCalls?.filter(
132
133
  (tc) => tc.name !== "task" && tc.name !== "ask_user"
133
134
  ) || []
134
135
 
136
+ // Split into reasoning tools (shown collapsed) and direct tools (shown normally)
137
+ const reasoningCalls = allToolCalls.filter((tc) => tc.visibility === "reasoning")
138
+ const directToolCalls = allToolCalls.filter((tc) => tc.visibility !== "reasoning")
139
+
135
140
  const hasContent = contentStr.trim() !== ""
136
- if (!hasContent && directToolCalls.length === 0 && subAgents.length === 0 && !message.isLoading) {
141
+ const hasReasoning = reasoningCalls.length > 0
142
+ const reasoningText = hasReasoning ? contentStr : undefined
143
+ const displayContentStr = hasReasoning ? "" : contentStr
144
+ const hasDisplayContent = displayContentStr.trim() !== ""
145
+
146
+ if (!hasDisplayContent && directToolCalls.length === 0 && reasoningCalls.length === 0 && subAgents.length === 0 && !message.isLoading) {
137
147
  return null;
138
148
  }
139
149
 
150
+ const isStreaming = reasoningCalls.some((tc) => tc.status === "pending")
151
+
140
152
  return (
141
153
  <OrchestratorMessage
142
154
  key={message.id}
143
155
  message={{
144
156
  id: message.id,
145
- content: contentStr,
157
+ content: displayContentStr,
146
158
  avatarSrc: message.avatarSrc,
147
159
  avatarName: message.avatarName,
148
- isLoading: message.isLoading,
160
+ isLoading: message.isLoading && !hasReasoning,
149
161
  }}
150
- showAvatar={showAvatars}
162
+ showAvatar={showAvatars && hasDisplayContent}
151
163
  >
164
+ {/* Render reasoning-section for hidden tool results */}
165
+ {hasReasoning && (
166
+ <ReasoningDisplay
167
+ content={reasoningText}
168
+ items={reasoningCalls}
169
+ isStreaming={isStreaming}
170
+ onToolAction={onToolAction}
171
+ />
172
+ )}
173
+
152
174
  {/* Render direct tool calls */}
153
175
  {directToolCalls.map((tc) => (
154
176
  <ToolCallDisplay key={tc.id} toolCall={tc} onToolAction={onToolAction} />
@@ -88,17 +88,36 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
88
88
  className,
89
89
  }) => {
90
90
  const [searchQuery, setSearchQuery] = React.useState("")
91
+ const [userExpanded, setUserExpanded] = React.useState<Set<string>>(defaultExpanded || new Set())
92
+
93
+ // Auto-expand parents when selectedPath changes
94
+ React.useEffect(() => {
95
+ if (selectedPath) {
96
+ const parts = selectedPath.split('/')
97
+ if (parts.length > 1) {
98
+ setUserExpanded(prev => {
99
+ const next = new Set(prev)
100
+ let currentPath = ''
101
+ for (let i = 0; i < parts.length - 1; i++) {
102
+ currentPath += (i === 0 ? '' : '/') + parts[i]
103
+ next.add(currentPath)
104
+ }
105
+ return next
106
+ })
107
+ }
108
+ }
109
+ }, [selectedPath])
91
110
 
92
111
  const filteredTree = React.useMemo(() => {
93
112
  return filterTree(tree, searchQuery)
94
113
  }, [tree, searchQuery])
95
114
 
96
- const expandedPaths = React.useMemo(() => {
115
+ const activeExpanded = React.useMemo(() => {
97
116
  if (searchQuery) {
98
117
  return getAllFolderPaths(filteredTree)
99
118
  }
100
- return defaultExpanded
101
- }, [searchQuery, filteredTree, defaultExpanded])
119
+ return userExpanded
120
+ }, [searchQuery, filteredTree, userExpanded])
102
121
 
103
122
  return (
104
123
  <div className={cn("flex flex-col rounded-lg border bg-background", className)}>
@@ -130,7 +149,8 @@ export const FileTreeExplorer = React.memo<FileTreeExplorerProps>(
130
149
  <div className="p-2">
131
150
  <FileTree
132
151
  className="border-none bg-transparent"
133
- defaultExpanded={expandedPaths}
152
+ expanded={activeExpanded}
153
+ onExpandedChange={setUserExpanded}
134
154
  selectedPath={selectedPath}
135
155
  onSelect={onSelect}
136
156
  >
@@ -0,0 +1,76 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import { ReasoningDisplay } from './ReasoningDisplay'
3
+
4
+ const meta: Meta<typeof ReasoningDisplay> = {
5
+ title: 'Composites/ReasoningDisplay',
6
+ component: ReasoningDisplay,
7
+ parameters: {
8
+ layout: 'padded',
9
+ },
10
+ } satisfies Meta<typeof ReasoningDisplay>
11
+
12
+ export default meta
13
+ type Story = StoryObj<typeof meta>
14
+
15
+ export const Default: Story = {
16
+ args: {
17
+ content: "Let me evaluate the user's request and read the necessary files to propose a solution.",
18
+ isStreaming: false,
19
+ items: [
20
+ {
21
+ id: 'tool_1',
22
+ name: 'read_file',
23
+ args: { file_path: '/workspace/src/main.tsx' },
24
+ result: 'import { App } from "./App"; ...',
25
+ status: 'completed',
26
+ visibility: 'reasoning',
27
+ uiVariant: 'link',
28
+ linkText: 'src/main.tsx',
29
+ linkAction: 'open-file',
30
+ },
31
+ {
32
+ id: 'tool_2',
33
+ name: 'read_file',
34
+ args: { file_path: '/workspace/src/App.tsx' },
35
+ result: 'export const App = () => <div>Hello</div>;',
36
+ status: 'completed',
37
+ visibility: 'reasoning',
38
+ uiVariant: 'link',
39
+ linkText: 'src/App.tsx',
40
+ linkAction: 'open-file',
41
+ }
42
+ ],
43
+ },
44
+ }
45
+
46
+ export const Streaming: Story = {
47
+ args: {
48
+ content: "I'll start by listing the directory contents...",
49
+ isStreaming: true,
50
+ items: [
51
+ {
52
+ id: 'tool_1',
53
+ name: 'list_dir',
54
+ args: { path: '/src' },
55
+ status: 'pending',
56
+ visibility: 'reasoning',
57
+ },
58
+ ],
59
+ },
60
+ }
61
+
62
+ export const OnlyTools: Story = {
63
+ args: {
64
+ isStreaming: false,
65
+ items: [
66
+ {
67
+ id: 'tool_1',
68
+ name: 'write_todos',
69
+ args: { todos: ['Fix layout', 'Update colors'] },
70
+ result: 'Todos written successfully.',
71
+ status: 'completed',
72
+ visibility: 'reasoning',
73
+ },
74
+ ],
75
+ },
76
+ }
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import {
4
+ Reasoning,
5
+ ReasoningTrigger,
6
+ } from "@/components/ai-elements/reasoning";
7
+ import { CollapsibleContent } from "@/components/primitives/Collapsible";
8
+ import { Response } from "@/components/ai-elements/response";
9
+ import { ToolCallDisplay } from "@/components/composites/ToolCallDisplay";
10
+ import type { ToolCall } from "@/components/composites/ToolCallDisplay";
11
+
12
+ export interface ReasoningDisplayProps {
13
+ items: ToolCall[];
14
+ isStreaming?: boolean;
15
+ content?: string;
16
+ onToolAction?: (toolCall: ToolCall, action: string) => void;
17
+ }
18
+
19
+ export const ReasoningDisplay = ({
20
+ items,
21
+ isStreaming = false,
22
+ content,
23
+ onToolAction,
24
+ }: ReasoningDisplayProps) => {
25
+ if (items.length === 0 && !content) return null;
26
+
27
+ return (
28
+ <Reasoning isStreaming={isStreaming} defaultOpen={false}>
29
+ <ReasoningTrigger />
30
+ <CollapsibleContent
31
+ className="mt-4 flex flex-col gap-2 data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in"
32
+ >
33
+ {content && content.trim() && (
34
+ <div className="mb-4">
35
+ <Response className="grid gap-2">{content}</Response>
36
+ </div>
37
+ )}
38
+ <div className="flex flex-col gap-2">
39
+ {items.map((item) => (
40
+ <ToolCallDisplay key={item.id} toolCall={item} onToolAction={onToolAction} />
41
+ ))}
42
+ </div>
43
+ </CollapsibleContent>
44
+ </Reasoning>
45
+ );
46
+ };
@@ -0,0 +1,2 @@
1
+ export { ReasoningDisplay } from './ReasoningDisplay'
2
+ export type { ReasoningDisplayProps } from './ReasoningDisplay'
@@ -21,6 +21,7 @@ export interface ToolCall {
21
21
  args: Record<string, unknown>
22
22
  result?: string
23
23
  status: "pending" | "completed" | "error"
24
+ visibility?: "visible" | "reasoning"
24
25
  uiVariant?: "default" | "link"
25
26
  linkText?: string
26
27
  linkAction?: string
@@ -9,6 +9,10 @@
9
9
  export { ToolCallDisplay } from './ToolCallDisplay'
10
10
  export type { ToolCallDisplayProps, ToolCall } from './ToolCallDisplay'
11
11
 
12
+ // ReasoningDisplay Block
13
+ export { ReasoningDisplay } from './ReasoningDisplay'
14
+ export type { ReasoningDisplayProps } from './ReasoningDisplay'
15
+
12
16
  // AgentIndicator Block
13
17
  export { AgentIndicator } from './AgentIndicator'
14
18
  export type { AgentIndicatorProps, SubAgent } from './AgentIndicator'
package/dist/index.cjs CHANGED
@@ -20,6 +20,7 @@ var useStickToBottom = require('use-stick-to-bottom');
20
20
  var radixUi = require('radix-ui');
21
21
  var shiki = require('shiki');
22
22
  var streamdown = require('streamdown');
23
+ var reactUseControllableState = require('@radix-ui/react-use-controllable-state');
23
24
  var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
24
25
  var HoverCardPrimitive = require('@radix-ui/react-hover-card');
25
26
  var SelectPrimitive = require('@radix-ui/react-select');
@@ -3407,6 +3408,202 @@ var OrchestratorMessage = React3__namespace.memo(
3407
3408
  }
3408
3409
  );
3409
3410
  OrchestratorMessage.displayName = "OrchestratorMessage";
3411
+ var ReasoningContext = React3.createContext(null);
3412
+ var useReasoning = () => {
3413
+ const context = React3.useContext(ReasoningContext);
3414
+ if (!context) {
3415
+ throw new Error("Reasoning components must be used within Reasoning");
3416
+ }
3417
+ return context;
3418
+ };
3419
+ var AUTO_CLOSE_DELAY = 1e3;
3420
+ var MS_IN_S = 1e3;
3421
+ var Reasoning = React3.memo(
3422
+ (_a) => {
3423
+ var _b = _a, {
3424
+ className,
3425
+ isStreaming = false,
3426
+ open,
3427
+ defaultOpen = true,
3428
+ onOpenChange,
3429
+ duration: durationProp,
3430
+ children
3431
+ } = _b, props = __objRest(_b, [
3432
+ "className",
3433
+ "isStreaming",
3434
+ "open",
3435
+ "defaultOpen",
3436
+ "onOpenChange",
3437
+ "duration",
3438
+ "children"
3439
+ ]);
3440
+ const [isOpen, setIsOpen] = reactUseControllableState.useControllableState({
3441
+ prop: open,
3442
+ defaultProp: defaultOpen,
3443
+ onChange: onOpenChange
3444
+ });
3445
+ const [duration, setDuration] = reactUseControllableState.useControllableState({
3446
+ prop: durationProp,
3447
+ defaultProp: 0
3448
+ });
3449
+ const [hasAutoClosed, setHasAutoClosed] = React3.useState(false);
3450
+ const [startTime, setStartTime] = React3.useState(null);
3451
+ React3.useEffect(() => {
3452
+ if (isStreaming) {
3453
+ if (startTime === null) {
3454
+ const timer = setTimeout(() => {
3455
+ setStartTime(Date.now());
3456
+ }, 0);
3457
+ return () => clearTimeout(timer);
3458
+ }
3459
+ } else if (startTime !== null) {
3460
+ const calculatedDuration = Math.ceil((Date.now() - startTime) / MS_IN_S);
3461
+ const timer = setTimeout(() => {
3462
+ setDuration(calculatedDuration);
3463
+ setStartTime(null);
3464
+ }, 0);
3465
+ return () => clearTimeout(timer);
3466
+ }
3467
+ return void 0;
3468
+ }, [isStreaming, startTime, setDuration]);
3469
+ React3.useEffect(() => {
3470
+ if (defaultOpen && !isStreaming && isOpen && !hasAutoClosed) {
3471
+ const timer = setTimeout(() => {
3472
+ setIsOpen(false);
3473
+ setHasAutoClosed(true);
3474
+ }, AUTO_CLOSE_DELAY);
3475
+ return () => clearTimeout(timer);
3476
+ }
3477
+ return void 0;
3478
+ }, [isStreaming, isOpen, defaultOpen, setIsOpen, hasAutoClosed]);
3479
+ const handleOpenChange = (newOpen) => {
3480
+ setIsOpen(newOpen);
3481
+ };
3482
+ return /* @__PURE__ */ jsxRuntime.jsx(
3483
+ ReasoningContext.Provider,
3484
+ {
3485
+ value: { isStreaming, isOpen, setIsOpen, duration },
3486
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3487
+ Collapsible,
3488
+ __spreadProps(__spreadValues({
3489
+ className: cn("not-prose mb-4", className),
3490
+ onOpenChange: handleOpenChange,
3491
+ open: isOpen
3492
+ }, props), {
3493
+ children
3494
+ })
3495
+ )
3496
+ }
3497
+ );
3498
+ }
3499
+ );
3500
+ var getThinkingMessage = (isStreaming, duration) => {
3501
+ if (isStreaming) {
3502
+ return /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 1, children: "Thinking..." });
3503
+ }
3504
+ if (duration === void 0 || duration === 0) {
3505
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Thought for a few seconds" });
3506
+ }
3507
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3508
+ "Thought for ",
3509
+ duration,
3510
+ " seconds"
3511
+ ] });
3512
+ };
3513
+ var ReasoningTrigger = React3.memo(
3514
+ (_a) => {
3515
+ var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
3516
+ const { isStreaming, isOpen, duration } = useReasoning();
3517
+ return /* @__PURE__ */ jsxRuntime.jsx(
3518
+ CollapsibleTrigger,
3519
+ __spreadProps(__spreadValues({
3520
+ className: cn(
3521
+ "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",
3522
+ className
3523
+ )
3524
+ }, props), {
3525
+ children: children != null ? children : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3526
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BrainIcon, { className: "size-4" }),
3527
+ getThinkingMessage(isStreaming, duration),
3528
+ /* @__PURE__ */ jsxRuntime.jsx(
3529
+ lucideReact.ChevronDownIcon,
3530
+ {
3531
+ className: cn(
3532
+ "size-4 transition-transform",
3533
+ isOpen ? "rotate-180" : "rotate-0"
3534
+ )
3535
+ }
3536
+ )
3537
+ ] })
3538
+ })
3539
+ );
3540
+ }
3541
+ );
3542
+ var ReasoningContent = React3.memo(
3543
+ (_a) => {
3544
+ var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
3545
+ return /* @__PURE__ */ jsxRuntime.jsx(
3546
+ CollapsibleContent,
3547
+ __spreadProps(__spreadValues({
3548
+ className: cn(
3549
+ "mt-4 text-sm",
3550
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
3551
+ className
3552
+ )
3553
+ }, props), {
3554
+ children: /* @__PURE__ */ jsxRuntime.jsx(Response, { className: "grid gap-2", children })
3555
+ })
3556
+ );
3557
+ }
3558
+ );
3559
+ Reasoning.displayName = "Reasoning";
3560
+ ReasoningTrigger.displayName = "ReasoningTrigger";
3561
+ ReasoningContent.displayName = "ReasoningContent";
3562
+ var Collapsible2 = React3__namespace.memo(
3563
+ React3__namespace.forwardRef(
3564
+ (props, ref) => {
3565
+ return /* @__PURE__ */ jsxRuntime.jsx(Collapsible, __spreadValues({}, props));
3566
+ }
3567
+ )
3568
+ );
3569
+ Collapsible2.displayName = "Collapsible";
3570
+ var CollapsibleTrigger2 = React3__namespace.memo(
3571
+ React3__namespace.forwardRef(
3572
+ (props, ref) => {
3573
+ return /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger, __spreadValues({ ref }, props));
3574
+ }
3575
+ )
3576
+ );
3577
+ CollapsibleTrigger2.displayName = "CollapsibleTrigger";
3578
+ var CollapsibleContent2 = React3__namespace.memo(
3579
+ React3__namespace.forwardRef(
3580
+ (props, ref) => {
3581
+ return /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent, __spreadValues({ ref }, props));
3582
+ }
3583
+ )
3584
+ );
3585
+ CollapsibleContent2.displayName = "CollapsibleContent";
3586
+ var ReasoningDisplay = ({
3587
+ items,
3588
+ isStreaming = false,
3589
+ content,
3590
+ onToolAction
3591
+ }) => {
3592
+ if (items.length === 0 && !content) return null;
3593
+ return /* @__PURE__ */ jsxRuntime.jsxs(Reasoning, { isStreaming, defaultOpen: false, children: [
3594
+ /* @__PURE__ */ jsxRuntime.jsx(ReasoningTrigger, {}),
3595
+ /* @__PURE__ */ jsxRuntime.jsxs(
3596
+ CollapsibleContent2,
3597
+ {
3598
+ className: "mt-4 flex flex-col gap-2 data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-muted-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
3599
+ children: [
3600
+ content && content.trim() && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsxRuntime.jsx(Response, { className: "grid gap-2", children: content }) }),
3601
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallDisplay, { toolCall: item, onToolAction }, item.id)) })
3602
+ ]
3603
+ }
3604
+ )
3605
+ ] });
3606
+ };
3410
3607
  var AIConversation = React3__namespace.memo(
3411
3608
  (_a) => {
3412
3609
  var _b = _a, {
@@ -3458,25 +3655,41 @@ var AIConversation = React3__namespace.memo(
3458
3655
  }
3459
3656
  if (message.role === "orchestrator") {
3460
3657
  const subAgents = message.subAgents || [];
3461
- const directToolCalls = ((_a2 = message.toolCalls) == null ? void 0 : _a2.filter(
3658
+ const allToolCalls = ((_a2 = message.toolCalls) == null ? void 0 : _a2.filter(
3462
3659
  (tc) => tc.name !== "task" && tc.name !== "ask_user"
3463
3660
  )) || [];
3464
- const hasContent = contentStr.trim() !== "";
3465
- if (!hasContent && directToolCalls.length === 0 && subAgents.length === 0 && !message.isLoading) {
3661
+ const reasoningCalls = allToolCalls.filter((tc) => tc.visibility === "reasoning");
3662
+ const directToolCalls = allToolCalls.filter((tc) => tc.visibility !== "reasoning");
3663
+ contentStr.trim() !== "";
3664
+ const hasReasoning = reasoningCalls.length > 0;
3665
+ const reasoningText = hasReasoning ? contentStr : void 0;
3666
+ const displayContentStr = hasReasoning ? "" : contentStr;
3667
+ const hasDisplayContent = displayContentStr.trim() !== "";
3668
+ if (!hasDisplayContent && directToolCalls.length === 0 && reasoningCalls.length === 0 && subAgents.length === 0 && !message.isLoading) {
3466
3669
  return null;
3467
3670
  }
3671
+ const isStreaming = reasoningCalls.some((tc) => tc.status === "pending");
3468
3672
  return /* @__PURE__ */ jsxRuntime.jsxs(
3469
3673
  OrchestratorMessage,
3470
3674
  {
3471
3675
  message: {
3472
3676
  id: message.id,
3473
- content: contentStr,
3677
+ content: displayContentStr,
3474
3678
  avatarSrc: message.avatarSrc,
3475
3679
  avatarName: message.avatarName,
3476
- isLoading: message.isLoading
3680
+ isLoading: message.isLoading && !hasReasoning
3477
3681
  },
3478
- showAvatar: showAvatars,
3682
+ showAvatar: showAvatars && hasDisplayContent,
3479
3683
  children: [
3684
+ hasReasoning && /* @__PURE__ */ jsxRuntime.jsx(
3685
+ ReasoningDisplay,
3686
+ {
3687
+ content: reasoningText,
3688
+ items: reasoningCalls,
3689
+ isStreaming,
3690
+ onToolAction
3691
+ }
3692
+ ),
3480
3693
  directToolCalls.map((tc) => /* @__PURE__ */ jsxRuntime.jsx(ToolCallDisplay, { toolCall: tc, onToolAction }, tc.id)),
3481
3694
  subAgents.map((subAgent) => /* @__PURE__ */ jsxRuntime.jsx(
3482
3695
  SpecialistMessage,
@@ -6475,30 +6688,6 @@ var ChartLegendContent2 = React3__namespace.memo(
6475
6688
  })
6476
6689
  );
6477
6690
  ChartLegendContent2.displayName = "ChartLegendContent";
6478
- var Collapsible2 = React3__namespace.memo(
6479
- React3__namespace.forwardRef(
6480
- (props, ref) => {
6481
- return /* @__PURE__ */ jsxRuntime.jsx(Collapsible, __spreadValues({}, props));
6482
- }
6483
- )
6484
- );
6485
- Collapsible2.displayName = "Collapsible";
6486
- var CollapsibleTrigger2 = React3__namespace.memo(
6487
- React3__namespace.forwardRef(
6488
- (props, ref) => {
6489
- return /* @__PURE__ */ jsxRuntime.jsx(CollapsibleTrigger, __spreadValues({ ref }, props));
6490
- }
6491
- )
6492
- );
6493
- CollapsibleTrigger2.displayName = "CollapsibleTrigger";
6494
- var CollapsibleContent2 = React3__namespace.memo(
6495
- React3__namespace.forwardRef(
6496
- (props, ref) => {
6497
- return /* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent, __spreadValues({ ref }, props));
6498
- }
6499
- )
6500
- );
6501
- CollapsibleContent2.displayName = "CollapsibleContent";
6502
6691
  var Drawer = (_a) => {
6503
6692
  var _b = _a, {
6504
6693
  shouldScaleBackground = true
@@ -10824,15 +11013,32 @@ var FileTreeExplorer = React3__namespace.memo(
10824
11013
  className
10825
11014
  }) => {
10826
11015
  const [searchQuery, setSearchQuery] = React3__namespace.useState("");
11016
+ const [userExpanded, setUserExpanded] = React3__namespace.useState(defaultExpanded || /* @__PURE__ */ new Set());
11017
+ React3__namespace.useEffect(() => {
11018
+ if (selectedPath) {
11019
+ const parts = selectedPath.split("/");
11020
+ if (parts.length > 1) {
11021
+ setUserExpanded((prev) => {
11022
+ const next = new Set(prev);
11023
+ let currentPath = "";
11024
+ for (let i = 0; i < parts.length - 1; i++) {
11025
+ currentPath += (i === 0 ? "" : "/") + parts[i];
11026
+ next.add(currentPath);
11027
+ }
11028
+ return next;
11029
+ });
11030
+ }
11031
+ }
11032
+ }, [selectedPath]);
10827
11033
  const filteredTree = React3__namespace.useMemo(() => {
10828
11034
  return filterTree(tree, searchQuery);
10829
11035
  }, [tree, searchQuery]);
10830
- const expandedPaths = React3__namespace.useMemo(() => {
11036
+ const activeExpanded = React3__namespace.useMemo(() => {
10831
11037
  if (searchQuery) {
10832
11038
  return getAllFolderPaths(filteredTree);
10833
11039
  }
10834
- return defaultExpanded;
10835
- }, [searchQuery, filteredTree, defaultExpanded]);
11040
+ return userExpanded;
11041
+ }, [searchQuery, filteredTree, userExpanded]);
10836
11042
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col rounded-lg border bg-background", className), children: [
10837
11043
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-2 border-b px-3 py-2", headerClassName), children: [
10838
11044
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1", children: [
@@ -10871,7 +11077,8 @@ var FileTreeExplorer = React3__namespace.memo(
10871
11077
  FileTree,
10872
11078
  {
10873
11079
  className: "border-none bg-transparent",
10874
- defaultExpanded: expandedPaths,
11080
+ expanded: activeExpanded,
11081
+ onExpandedChange: setUserExpanded,
10875
11082
  selectedPath,
10876
11083
  onSelect,
10877
11084
  children: renderTree(filteredTree)