File tree Expand file tree Collapse file tree 3 files changed +47
-4
lines changed Expand file tree Collapse file tree 3 files changed +47
-4
lines changed Original file line number Diff line number Diff line change @@ -102,10 +102,18 @@ export const FileEditToolCall: React.FC<FileEditToolCallProps> = ({
102102 const isWriteDenied = result && ! result . success && result . error ?. startsWith ( WRITE_DENIED_PREFIX ) ;
103103 const initialExpanded = ! isWriteDenied ;
104104
105- const { expanded, toggleExpanded } = useToolExpansion ( initialExpanded ) ;
105+ const { expanded, setExpanded , toggleExpanded } = useToolExpansion ( initialExpanded ) ;
106106 const [ showRaw , setShowRaw ] = React . useState ( false ) ;
107107 const [ copied , setCopied ] = React . useState ( false ) ;
108108
109+ // Update expanded state when result changes from undefined to WRITE DENIED
110+ // This handles the case where the component renders before the result is available
111+ React . useEffect ( ( ) => {
112+ if ( result && ! result . success && result . error ?. startsWith ( WRITE_DENIED_PREFIX ) ) {
113+ setExpanded ( false ) ;
114+ }
115+ } , [ result , setExpanded ] ) ;
116+
109117 const filePath = "file_path" in args ? args . file_path : undefined ;
110118
111119 const handleCopyPatch = async ( ) => {
Original file line number Diff line number Diff line change @@ -33,6 +33,18 @@ export const GenericToolCall: React.FC<GenericToolCallProps> = ({
3333} ) => {
3434 const { expanded, toggleExpanded } = useToolExpansion ( ) ;
3535
36+ // Check if result contains an error
37+ // Handles two formats:
38+ // 1. Tool implementation errors: { success: false, error: "..." }
39+ // 2. AI SDK tool-error events: { error: "..." }
40+ const hasError =
41+ result &&
42+ typeof result === "object" &&
43+ "error" in result &&
44+ typeof result . error === "string" &&
45+ result . error . length > 0 &&
46+ ( ! ( "success" in result ) || result . success === false ) ;
47+
3648 const hasDetails = args !== undefined || result !== undefined ;
3749
3850 return (
@@ -52,7 +64,16 @@ export const GenericToolCall: React.FC<GenericToolCallProps> = ({
5264 </ DetailSection >
5365 ) }
5466
55- { result !== undefined && (
67+ { hasError ? (
68+ < DetailSection >
69+ < DetailLabel > Error</ DetailLabel >
70+ < div className = "text-danger bg-danger-overlay border-danger rounded border-l-2 px-2 py-1.5 text-[11px]" >
71+ { String ( ( result as { error : string } ) . error ) }
72+ </ div >
73+ </ DetailSection >
74+ ) : null }
75+
76+ { result !== undefined && ! hasError && (
5677 < DetailSection >
5778 < DetailLabel > Result</ DetailLabel >
5879 < DetailContent > { formatValue ( result ) } </ DetailContent >
Original file line number Diff line number Diff line change @@ -673,8 +673,22 @@ export class StreamingMessageAggregator {
673673 timestamp : part . timestamp ?? baseTimestamp ,
674674 } ) ;
675675 } else if ( isDynamicToolPart ( part ) ) {
676- const status =
677- part . state === "output-available"
676+ // Check if output contains an error
677+ // Handles two formats:
678+ // 1. Tool implementation errors: { success: false, error: "..." }
679+ // 2. AI SDK tool-error events: { error: "..." }
680+ const hasError =
681+ part . state === "output-available" &&
682+ part . output &&
683+ typeof part . output === "object" &&
684+ "error" in part . output &&
685+ typeof part . output . error === "string" &&
686+ part . output . error . length > 0 &&
687+ ( ! ( "success" in part . output ) || part . output . success === false ) ;
688+
689+ const status = hasError
690+ ? "failed"
691+ : part . state === "output-available"
678692 ? "completed"
679693 : part . state === "input-available" && message . metadata ?. partial
680694 ? "interrupted"
You can’t perform that action at this time.
0 commit comments