@@ -398,7 +398,6 @@ async def main(message: cl.Message):
398398 message_history .append ({"role" : "user" , "content" : user_message })
399399
400400 msg = cl .Message (content = "" )
401- await msg .send ()
402401
403402 # Use PraisonAI Agents if available, otherwise fallback to litellm
404403 if PRAISONAI_AGENTS_AVAILABLE :
@@ -433,48 +432,55 @@ async def handle_with_praisonai_agents(message, user_message, model_name, claude
433432
434433For informational questions, explanations, or general conversations, respond normally without using Claude Code."""
435434
436- # Create agent
435+ # Create agent with streaming enabled
437436 agent = Agent (
438437 name = "PraisonAI Assistant" ,
439438 instructions = instructions ,
440439 llm = model_name ,
441- tools = available_tools if available_tools else None
440+ tools = available_tools if available_tools else None ,
441+ stream = True
442442 )
443443
444444 # Execute agent with streaming
445445 full_response = ""
446+ msg_sent = False
446447
447- # Use agent's streaming capabilities if available
448448 try :
449- # For now, use synchronous execution and stream the result
450- # TODO: Implement proper streaming when PraisonAI agents support it
451- result = agent .start (user_message )
449+ # Use async chat for proper streaming
450+ result = await agent .achat (user_message )
452451
453- # Stream the response character by character for better UX
452+ # Get the response text
454453 if hasattr (result , 'raw' ):
455454 response_text = result .raw
456455 else :
457456 response_text = str (result )
458457
459- for char in response_text :
460- await msg .stream_token (char )
461- full_response += char
462- # Small delay to make streaming visible
463- await asyncio .sleep (0.01 )
458+ # Send message on first content
459+ if not msg_sent :
460+ await msg .send ()
461+ msg_sent = True
462+
463+ # Stream in word chunks for better UX (not char-by-char which is too slow)
464+ words = response_text .split (' ' )
465+ for i , word in enumerate (words ):
466+ token = word + (' ' if i < len (words ) - 1 else '' )
467+ await msg .stream_token (token )
468+ full_response += token
464469
465470 except Exception as e :
466471 error_response = f"Error executing agent: { str (e )} "
467- for char in error_response :
468- await msg .stream_token ( char )
469- full_response += char
470- await asyncio . sleep ( 0.01 )
472+ if not msg_sent :
473+ await msg .send ( )
474+ await msg . stream_token ( error_response )
475+ full_response = error_response
471476
472477 msg .content = full_response
473478 await msg .update ()
474479
475480 except Exception as e :
476481 error_msg = f"Failed to use PraisonAI Agents: { str (e )} "
477482 logger .error (error_msg )
483+ await msg .send ()
478484 await msg .stream_token (error_msg )
479485 msg .content = error_msg
480486 await msg .update ()
@@ -515,6 +521,7 @@ async def handle_with_litellm(user_message, model_name, message_history, msg, im
515521 full_response = ""
516522 tool_calls = []
517523 current_tool_call = None
524+ msg_sent = False
518525
519526 async for part in response :
520527 logger .debug (f"LLM part: { part } " )
@@ -523,6 +530,10 @@ async def handle_with_litellm(user_message, model_name, message_history, msg, im
523530
524531 if 'content' in delta and delta ['content' ] is not None :
525532 token = delta ['content' ]
533+ # Send message on first token
534+ if not msg_sent :
535+ await msg .send ()
536+ msg_sent = True
526537 await msg .stream_token (token )
527538 full_response += token
528539
@@ -549,6 +560,10 @@ async def handle_with_litellm(user_message, model_name, message_history, msg, im
549560 if current_tool_call :
550561 tool_calls .append (current_tool_call )
551562
563+ # Ensure message is sent even if no content (tool calls only)
564+ if not msg_sent :
565+ await msg .send ()
566+
552567 logger .debug (f"Full response: { full_response } " )
553568 logger .debug (f"Tool calls: { tool_calls } " )
554569 message_history .append ({"role" : "assistant" , "content" : full_response })
0 commit comments