@@ -394,20 +394,44 @@ async def apiChatStream(request: Request):
394394 if sessionId :
395395 executor .setActiveSession (sessionId )
396396
397+ async def _yieldTokenStream (messages ):
398+ loop = asyncio .get_running_loop ()
399+ queue : asyncio .Queue [str | None ] = asyncio .Queue ()
400+
401+ def _runStream ():
402+ try :
403+ for token in llmProvider .stream (messages ):
404+ loop .call_soon_threadsafe (queue .put_nowait , token )
405+ finally :
406+ loop .call_soon_threadsafe (queue .put_nowait , None )
407+
408+ thread = threading .Thread (target = _runStream , daemon = True )
409+ thread .start ()
410+
411+ accumulated = ""
412+ while True :
413+ token = await queue .get ()
414+ if token is None :
415+ break
416+ accumulated += token
417+ yield f"data: { json .dumps ({'type' : 'token' , 'content' : accumulated }, ensure_ascii = False )} \n \n "
418+
419+ convManager .addAssistantMessage (conversationId , accumulated )
420+ yield f"data: { json .dumps ({'type' : 'done' , 'answer' : accumulated , 'provider' : llmProvider .config .provider , 'model' : llmProvider .resolvedModel , 'usage' : None , 'toolCalls' : []}, ensure_ascii = False )} \n \n "
421+ thread .join (timeout = 2 )
422+
397423 async def _streamGenerate ():
398424 nonlocal msgs , conversationId
399425 yield f"data: { json .dumps ({'type' : 'start' , 'conversationId' : conversationId }, ensure_ascii = False )} \n \n "
400426
427+ if not (llmProvider .supportsNativeTools and tools ):
428+ async for chunk in _yieldTokenStream (msgs ):
429+ yield chunk
430+ return
431+
401432 maxToolRounds = 10
402433 for _round in range (maxToolRounds ):
403- if llmProvider .supportsNativeTools and tools :
404- response = llmProvider .completeWithTools (msgs , tools )
405- else :
406- response = llmProvider .complete (msgs )
407- convManager .addAssistantMessage (conversationId , response .answer )
408- yield f"data: { json .dumps ({'type' : 'token' , 'content' : response .answer }, ensure_ascii = False )} \n \n "
409- yield f"data: { json .dumps ({'type' : 'done' , 'answer' : response .answer , 'provider' : response .provider , 'model' : response .model , 'usage' : response .usage , 'toolCalls' : []}, ensure_ascii = False )} \n \n "
410- return
434+ response = llmProvider .completeWithTools (msgs , tools )
411435
412436 if not response .toolCalls :
413437 convManager .addAssistantMessage (conversationId , response .answer )
@@ -435,10 +459,8 @@ async def _streamGenerate():
435459
436460 yield f"data: { json .dumps ({'type' : 'tool_results' , 'toolCalls' : toolResults }, ensure_ascii = False )} \n \n "
437461
438- finalResponse = llmProvider .complete (msgs )
439- convManager .addAssistantMessage (conversationId , finalResponse .answer )
440- yield f"data: { json .dumps ({'type' : 'token' , 'content' : finalResponse .answer }, ensure_ascii = False )} \n \n "
441- yield f"data: { json .dumps ({'type' : 'done' , 'answer' : finalResponse .answer , 'provider' : finalResponse .provider , 'model' : finalResponse .model , 'usage' : finalResponse .usage , 'toolCalls' : []}, ensure_ascii = False )} \n \n "
462+ async for chunk in _yieldTokenStream (msgs ):
463+ yield chunk
442464
443465 return StreamingResponse (_streamGenerate (), media_type = "text/event-stream" )
444466
0 commit comments