@@ -62,7 +62,12 @@ function formatToolArgs(input: unknown): string {
6262 return entries
6363 . slice ( 0 , 4 )
6464 . map ( ( [ k , v ] ) => {
65- const val = typeof v === 'string' ? v : JSON . stringify ( v ) ;
65+ let val : string ;
66+ try {
67+ val = typeof v === 'string' ? v : ( JSON . stringify ( v ) ?? String ( v ) ) ;
68+ } catch {
69+ val = String ( v ) ;
70+ }
6671 const display = val . length > 30 ? val . slice ( 0 , 30 ) + '…' : val ;
6772 return `${ k } : ${ display } ` ;
6873 } )
@@ -80,7 +85,12 @@ function isToolPart(part: UIMessage['parts'][number]): part is Extract<UIMessage
8085 * Format tool output for display, truncating to a max length.
8186 */
8287function formatToolOutput ( output : unknown , maxLen = 80 ) : string {
83- const raw = typeof output === 'string' ? output : JSON . stringify ( output ) ;
88+ let raw : string ;
89+ try {
90+ raw = typeof output === 'string' ? output : ( JSON . stringify ( output ) ?? '' ) ;
91+ } catch {
92+ raw = String ( output ?? '' ) ;
93+ }
8494 return raw . length > maxLen ? raw . slice ( 0 , maxLen ) + '…' : raw ;
8595}
8696
@@ -284,6 +294,18 @@ export function AiChatPanel() {
284294 const baseUrl = getApiBaseUrl ( ) ;
285295 const { agents, loading : agentsLoading } = useAgentList ( baseUrl ) ;
286296
297+ // Validate persisted agent against fetched list — fall back to general
298+ // chat if the previously selected agent is no longer available.
299+ useEffect ( ( ) => {
300+ if ( agentsLoading ) return ;
301+ if ( selectedAgent === GENERAL_CHAT_VALUE ) return ;
302+ const isValid = agents . some ( ( a ) => a . name === selectedAgent ) ;
303+ if ( ! isValid ) {
304+ setSelectedAgent ( GENERAL_CHAT_VALUE ) ;
305+ saveSelectedAgent ( GENERAL_CHAT_VALUE ) ;
306+ }
307+ } , [ agents , agentsLoading , selectedAgent ] ) ;
308+
287309 const initialMessages = useMemo ( ( ) => loadMessages ( ) as UIMessage [ ] , [ ] ) ;
288310
289311 const transport = useMemo (
0 commit comments