diff --git a/src/web/chat/components/ToolRendering/ToolCollapse.tsx b/src/web/chat/components/ToolRendering/ToolCollapse.tsx
new file mode 100644
index 00000000..1a57c37f
--- /dev/null
+++ b/src/web/chat/components/ToolRendering/ToolCollapse.tsx
@@ -0,0 +1,42 @@
+import React, { useState } from 'react';
+import { CornerDownRight } from 'lucide-react';
+import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/web/chat/components/ui/collapsible';
+
+interface ToolCollapseProps {
+ summaryText: string;
+ defaultExpanded?: boolean;
+ children: React.ReactNode;
+ ariaLabel?: string;
+}
+
+export function ToolCollapse({
+ summaryText,
+ defaultExpanded = false,
+ children,
+ ariaLabel
+}: ToolCollapseProps) {
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
+
+ return (
+
+
+
+
+
+ {summaryText}
+
+
+
+
+ {children}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/BashTool.tsx b/src/web/chat/components/ToolRendering/tools/BashTool.tsx
index 260fca4d..8b1a4032 100644
--- a/src/web/chat/components/ToolRendering/tools/BashTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/BashTool.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import { CodeHighlight } from '../../CodeHighlight';
+import { ToolCollapse } from '../ToolCollapse';
interface BashToolProps {
input: any;
@@ -9,13 +10,17 @@ interface BashToolProps {
export function BashTool({ input, result }: BashToolProps) {
return (
-
+
-
+
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/EditTool.tsx b/src/web/chat/components/ToolRendering/tools/EditTool.tsx
index 9c180c79..0ee5ceeb 100644
--- a/src/web/chat/components/ToolRendering/tools/EditTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/EditTool.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import { detectLanguageFromPath } from '../../../utils/language-detection';
import { CodeHighlight } from '../../CodeHighlight';
import { DiffViewer } from './DiffViewer';
+import { ToolCollapse } from '../ToolCollapse';
interface EditToolProps {
input: any;
@@ -14,54 +15,60 @@ export function EditTool({ input, result, isMultiEdit = false, workingDirectory
// 从文件路径检测语言
const filePath = input?.file_path || '';
const language = detectLanguageFromPath(filePath);
- // For MultiEdit, process all edits
- if (isMultiEdit && input.edits && Array.isArray(input.edits)) {
- return (
-
- {input.edits.map((edit: any, index: number) => (
-
-
- {index < input.edits.length - 1 && (
-
- )}
-
- ))}
-
- );
- }
+
+ const renderContent = () => {
+ // For MultiEdit, process all edits
+ if (isMultiEdit && input.edits && Array.isArray(input.edits)) {
+ return (
+
+ {input.edits.map((edit: any, index: number) => (
+
+
+ {index < input.edits.length - 1 && (
+
+ )}
+
+ ))}
+
+ );
+ }
- // For regular Edit, process single edit
- if (input.old_string !== undefined && input.new_string !== undefined) {
- return (
-
+ // For regular Edit, process single edit
+ if (input.old_string !== undefined && input.new_string !== undefined) {
+ return (
+ );
+ }
+
+ // Fallback if we can't parse the edit
+ return result ? (
+
+ ) : (
+
+
Edit completed successfully
);
- }
+ };
- // Fallback if we can't parse the edit
-
return (
-
- {result ? (
-
- ) : (
-
-
Edit completed successfully
-
- )}
-
+
+ {renderContent()}
+
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/FallbackTool.tsx b/src/web/chat/components/ToolRendering/tools/FallbackTool.tsx
index 65e61450..34ed5613 100644
--- a/src/web/chat/components/ToolRendering/tools/FallbackTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/FallbackTool.tsx
@@ -1,6 +1,5 @@
-import React, { useState } from 'react';
-import { CornerDownRight } from 'lucide-react';
-import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/web/chat/components/ui/collapsible';
+import React from 'react';
+import { ToolCollapse } from '../ToolCollapse';
interface FallbackToolProps {
toolName: string;
@@ -9,8 +8,6 @@ interface FallbackToolProps {
}
export function FallbackTool({ toolName, input, result }: FallbackToolProps) {
- const [isExpanded, setIsExpanded] = useState(false);
-
const formatContent = (content: string): string => {
try {
// Try to parse and format as JSON if possible
@@ -23,41 +20,30 @@ export function FallbackTool({ toolName, input, result }: FallbackToolProps) {
};
return (
-
-
-
-
-
- {toolName} completed
+
+
+ {result && (
+
+
+ {formatContent(result || 'No result')}
+
-
+ )}
-
- {result && (
-
-
- {formatContent(result || 'No result')}
-
-
- )}
-
- {/* Always show input in expanded state for debugging */}
- {input && (
-
-
Input:
-
- {JSON.stringify(input, null, 2)}
-
-
- )}
-
-
-
+ {/* Always show input in expanded state for debugging */}
+ {input && (
+
+
Input:
+
+ {JSON.stringify(input, null, 2)}
+
+
+ )}
+
+
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/PlanTool.tsx b/src/web/chat/components/ToolRendering/tools/PlanTool.tsx
index 8b50ab45..6088649e 100644
--- a/src/web/chat/components/ToolRendering/tools/PlanTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/PlanTool.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import ReactMarkdown from 'react-markdown';
+import { ToolCollapse } from '../ToolCollapse';
interface PlanToolProps {
input: any;
@@ -11,7 +12,11 @@ export function PlanTool({ input, result }: PlanToolProps) {
const planContent = input.plan || result || 'No plan provided';
return (
-
+
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/ReadTool.tsx b/src/web/chat/components/ToolRendering/tools/ReadTool.tsx
index 243e6380..bf15f58f 100644
--- a/src/web/chat/components/ToolRendering/tools/ReadTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/ReadTool.tsx
@@ -1,9 +1,8 @@
-import React, { useState } from 'react';
-import { CornerDownRight } from 'lucide-react';
+import React from 'react';
import { countLines } from '../../../utils/tool-utils';
import { detectLanguageFromPath } from '../../../utils/language-detection';
import { CodeHighlight } from '../../CodeHighlight';
-import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/web/chat/components/ui/collapsible';
+import { ToolCollapse } from '../ToolCollapse';
interface ReadToolProps {
input: any;
@@ -27,35 +26,25 @@ export function ReadTool({ input, result, workingDirectory }: ReadToolProps) {
return ;
}
- const [isExpanded, setIsExpanded] = useState(false);
-
const cleanedContent = cleanFileContent(result);
const lineCount = countLines(cleanedContent);
const filePath = input?.file_path || '';
const language = detectLanguageFromPath(filePath);
return (
-
-
-
-
- Read {lineCount} line{lineCount !== 1 ? 's' : ''}
-
-
-
- {cleanedContent && (
-
- )}
-
-
-
+
+ {cleanedContent && (
+
+ )}
+
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/SearchTool.tsx b/src/web/chat/components/ToolRendering/tools/SearchTool.tsx
index 2bebb205..5dff5fde 100644
--- a/src/web/chat/components/ToolRendering/tools/SearchTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/SearchTool.tsx
@@ -1,7 +1,6 @@
-import React, { useState } from 'react';
-import { CornerDownRight } from 'lucide-react';
+import React from 'react';
import { countLines, extractFileCount } from '../../../utils/tool-utils';
-import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/web/chat/components/ui/collapsible';
+import { ToolCollapse } from '../ToolCollapse';
interface SearchToolProps {
input: any;
@@ -10,8 +9,6 @@ interface SearchToolProps {
}
export function SearchTool({ input, result, toolType }: SearchToolProps) {
- const [isExpanded, setIsExpanded] = useState(false);
-
const getSummaryText = (): string => {
switch (toolType) {
case 'Grep':
@@ -32,29 +29,16 @@ export function SearchTool({ input, result, toolType }: SearchToolProps) {
};
return (
-
-
-
-
-
- {getSummaryText()}
-
-
-
-
- {result && (
-
- )}
-
-
-
+
+ {result && (
+
+ )}
+
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/WebTool.tsx b/src/web/chat/components/ToolRendering/tools/WebTool.tsx
index 78fa63de..4890baf6 100644
--- a/src/web/chat/components/ToolRendering/tools/WebTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/WebTool.tsx
@@ -1,7 +1,7 @@
-import React, { useState } from 'react';
-import { CornerDownRight, Globe } from 'lucide-react';
+import React from 'react';
+import { Globe } from 'lucide-react';
import { extractDomain } from '../../../utils/tool-utils';
-import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/web/chat/components/ui/collapsible';
+import { ToolCollapse } from '../ToolCollapse';
interface WebToolProps {
input: any;
@@ -10,8 +10,6 @@ interface WebToolProps {
}
export function WebTool({ input, result, toolType }: WebToolProps) {
- const [isExpanded, setIsExpanded] = useState(false);
-
const getSummaryText = (): string => {
if (toolType === 'WebSearch') {
// Could potentially extract timing information from result if available
@@ -52,30 +50,18 @@ export function WebTool({ input, result, toolType }: WebToolProps) {
return (
-
-
-
-
- {getSummaryText()}
+
+ {result && (
+
-
-
- {getDomainPills()}
-
-
- {result && (
-
- )}
-
-
+ )}
+
+ {getDomainPills()}
);
}
\ No newline at end of file
diff --git a/src/web/chat/components/ToolRendering/tools/WriteTool.tsx b/src/web/chat/components/ToolRendering/tools/WriteTool.tsx
index b02b14c8..c0887333 100644
--- a/src/web/chat/components/ToolRendering/tools/WriteTool.tsx
+++ b/src/web/chat/components/ToolRendering/tools/WriteTool.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import { detectLanguageFromPath } from '../../../utils/language-detection';
import { DiffViewer } from './DiffViewer';
+import { ToolCollapse } from '../ToolCollapse';
interface WriteToolProps {
input: any;
@@ -14,12 +15,16 @@ export function WriteTool({ input, result, workingDirectory }: WriteToolProps) {
const language = detectLanguageFromPath(filePath);
return (
-
+
-
+
);
}
\ No newline at end of file