55import sqlparse
66import streamlit as st
77from loguru import logger
8+ from streamlit .delta_generator import DeltaGenerator
89from streamlit_extras .stylable_container import stylable_container
910
1011from frontend .api import APIClient
@@ -279,14 +280,15 @@ def render(self):
279280 with st .chat_message ("assistant" , avatar = BD_LOGO ):
280281 st .empty ()
281282
282- if message_pair .assistant_message is not None :
283- label , state = "Concluído!" , "complete"
284- else :
285- label , state = "Erro" , "error"
283+ if _has_tool_events (message_pair .events ):
284+ if message_pair .assistant_message is not None :
285+ label , state = "Concluído! Clique para ver os detalhes" , "complete"
286+ else :
287+ label , state = "Erro" , "error"
286288
287- with st .status (label = label , state = state ) as status :
288- for event in message_pair .events :
289- _display_tool_event (event )
289+ with st .status (label = label , state = state ):
290+ for event in message_pair .events :
291+ _display_tool_event (event )
290292
291293 if message_pair .assistant_message is not None :
292294 st .write (message_pair .formatted_assistant_message )
@@ -319,33 +321,40 @@ def render(self):
319321 # Display assistant response in chat message container
320322 with st .chat_message ("assistant" , avatar = BD_LOGO ):
321323 events = []
322- assistant_message = None
323324 error_message = None
325+ assistant_message = None
326+ status_placeholder = st .empty ()
324327
325- with st .status ("Consultando a Base dos Dados..." ) as status :
326- for event in self .api .send_message (
327- access_token = st .session_state ["access_token" ],
328- message = user_prompt ,
329- thread_id = self .thread_id
330- ):
331- events .append (event )
332- if event .type == "final_answer" :
333- assistant_message = event .data .content
334- label , state = "Concluído!" , "complete"
335- elif event .type == "error" :
336- error_message = event .data .error_details .get ("message" , "Erro" )
337- label , state = "Erro" , "error"
338- elif event .type == "complete" :
339- message_pair = MessagePair (
340- id = event .data .run_id ,
341- user_message = user_prompt ,
342- assistant_message = assistant_message ,
343- error_message = error_message ,
344- events = events
345- )
328+ status = status_placeholder .status ("Pensando..." )
329+
330+ for event in self .api .send_message (
331+ access_token = st .session_state ["access_token" ],
332+ message = user_prompt ,
333+ thread_id = self .thread_id
334+ ):
335+ events .append (event )
336+
337+ if event .type == "final_answer" :
338+ assistant_message = event .data .content
339+ label , state = "Concluído! Clique para ver os detalhes" , "complete"
340+ elif event .type == "error" :
341+ error_message = event .data .error_details .get ("message" , "Erro" )
342+ label , state = "Erro" , "error"
343+ elif event .type == "complete" :
344+ message_pair = MessagePair (
345+ id = event .data .run_id ,
346+ user_message = user_prompt ,
347+ assistant_message = assistant_message ,
348+ error_message = error_message ,
349+ events = events
350+ )
351+ if _has_tool_events (message_pair .events ):
346352 status .update (label = label , state = state )
347353 else :
348- _display_tool_event (event )
354+ status_placeholder .empty ()
355+ else :
356+ status .update (label = "Consultando a Base dos Dados..." )
357+ _display_tool_event (event , container = status )
349358
350359 if message_pair .assistant_message is not None :
351360 st .write_stream (message_pair .stream_words )
@@ -402,7 +411,24 @@ def _clear_new_chat_page():
402411 st .session_state [NEW_CHAT ] = None
403412
404413
405- def _display_code_block (code_block : str , max_lines : int = 10 , max_height : int = 256 ):
414+ def _has_tool_events (events : list [StreamEvent ]) -> bool :
415+ """Check if there are any tool-related events in the event list.
416+
417+ Args:
418+ events (list[StreamEvent]): List of stream events.
419+
420+ Returns:
421+ bool: True if there are tool_call or tool_output events, False otherwise.
422+ """
423+ return any (event .type in ("tool_call" , "tool_output" ) for event in events )
424+
425+
426+ def _display_code_block (
427+ code_block : str ,
428+ max_lines : int = 10 ,
429+ max_height : int = 256 ,
430+ container : DeltaGenerator | None = None
431+ ):
406432 """Display a code block in Streamlit with adaptive height.
407433
408434 If the code block has more lines than `max_lines`, the display height
@@ -415,15 +441,19 @@ def _display_code_block(code_block: str, max_lines: int=10, max_height: int=256)
415441 before capping the height. Defaults to 10.
416442 max_height (int, optional): Maximum height in pixels for code blocks
417443 exceeding `max_lines`. Defaults to 256.
444+ container (DeltaGenerator | None, optional): Streamlit container
445+ to render into. If None, uses st directly. Defaults to None.
418446 """
447+ ctx = container if container is not None else st
448+
419449 n_lines = code_block .count ("\n " ) + 1
420450
421451 if n_lines > max_lines :
422452 height = max_height
423453 else :
424454 height = "content"
425455
426- st .code (code_block , height = height )
456+ ctx .code (code_block , height = height )
427457
428458
429459def _format_tool_args (args : dict [str , Any ]) -> str :
@@ -470,28 +500,32 @@ def _format_tool_outputs(results: str) -> str:
470500 )
471501
472502
473- def _display_tool_event (event : StreamEvent ):
503+ def _display_tool_event (event : StreamEvent , container : DeltaGenerator | None = None ):
474504 """Render a tool-related event in the Streamlit UI.
475505
476506 Displays messages, tool call arguments, and tool outputs
477507 with appropriate formatting and code block sizing.
478508
479509 Args:
480510 event (StreamEvent): The tool event to display.
511+ container (DeltaGenerator | None, optional): Streamlit container
512+ to render into. If None, uses st directly. Defaults to None.
481513 """
514+ ctx = container if container is not None else st
515+
482516 if event .type == "tool_call" :
483517 if event .data .content :
484- st .markdown (event .data .content )
518+ ctx .markdown (event .data .content )
485519 for tool_call in event .data .tool_calls :
486- st .markdown (f"**Executando ferramenta** `{ tool_call .name } `" )
520+ ctx .markdown (f"**Executando ferramenta** `{ tool_call .name } `" )
487521 tool_args = _format_tool_args (tool_call .args )
488- _display_code_block (f"Solicitação:\n { tool_args } " )
522+ _display_code_block (f"Solicitação:\n { tool_args } " , container = ctx )
489523 elif event .type == "tool_output" :
490524 for tool_output in event .data .tool_outputs :
491525 if tool_output .status == "error" :
492- st .markdown (f"Erro na execução da ferramenta `{ tool_output .tool_name } `" )
526+ ctx .markdown (f"Erro na execução da ferramenta `{ tool_output .tool_name } `" )
493527 else :
494528 if tool_output .metadata and tool_output .metadata .get ("truncated" ):
495- st .info ("Resposta muito extensa. Exibindo resultados parciais." , icon = ":material/info:" )
529+ ctx .info ("Resposta muito extensa. Exibindo resultados parciais." , icon = ":material/info:" )
496530 tool_outputs = _format_tool_outputs (tool_output .output )
497- _display_code_block (f"Resposta:\n { tool_outputs } " )
531+ _display_code_block (f"Resposta:\n { tool_outputs } " , container = ctx )
0 commit comments