@@ -215,7 +215,8 @@ class Agent:
215215 preset_stopping_token (bool): Enable preset stopping token
216216 traceback (Any): The traceback
217217 traceback_handlers (Any): The traceback handlers
218- streaming_on (bool): Enable streaming
218+ streaming_on (bool): Enable basic streaming with formatted panels
219+ stream (bool): Enable detailed token-by-token streaming with metadata (citations, tokens used, etc.)
219220 docs (List[str]): The list of documents
220221 docs_folder (str): The folder containing the documents
221222 verbose (bool): Enable verbose mode
@@ -307,9 +308,9 @@ class Agent:
307308 >>> print(response)
308309 >>> # Generate a report on the financials.
309310
310- >>> # Real-time streaming example
311- >>> agent = Agent(model_name="gpt-4.1", max_loops=1, streaming_on =True)
312- >>> response = agent.run("Tell me a long story.") # Will stream in real-time
311+ >>> # Detailed token streaming example
312+ >>> agent = Agent(model_name="gpt-4.1", max_loops=1, stream =True)
313+ >>> response = agent.run("Tell me a story.") # Will stream each token with detailed metadata
313314 >>> print(response) # Final complete response
314315
315316 >>> # Fallback model example
@@ -363,6 +364,7 @@ def __init__(
363364 traceback : Optional [Any ] = None ,
364365 traceback_handlers : Optional [Any ] = None ,
365366 streaming_on : Optional [bool ] = False ,
367+ stream : Optional [bool ] = False ,
366368 docs : List [str ] = None ,
367369 docs_folder : Optional [str ] = None ,
368370 verbose : Optional [bool ] = False ,
@@ -512,6 +514,7 @@ def __init__(
512514 self .traceback = traceback
513515 self .traceback_handlers = traceback_handlers
514516 self .streaming_on = streaming_on
517+ self .stream = stream
515518 self .docs = docs
516519 self .docs_folder = docs_folder
517520 self .verbose = verbose
@@ -1317,6 +1320,8 @@ def _run(
13171320 )
13181321 elif self .streaming_on :
13191322 pass
1323+ elif self .stream :
1324+ pass
13201325 else :
13211326 self .pretty_print (
13221327 response , loop_count
@@ -2537,8 +2542,105 @@ def call_llm(
25372542 del kwargs ["is_last" ]
25382543
25392544 try :
2540- # Set streaming parameter in LLM if streaming is enabled
2541- if self .streaming_on and hasattr (self .llm , "stream" ):
2545+ if self .stream and hasattr (self .llm , "stream" ):
2546+ original_stream = self .llm .stream
2547+ self .llm .stream = True
2548+
2549+ if img is not None :
2550+ streaming_response = self .llm .run (
2551+ task = task , img = img , * args , ** kwargs
2552+ )
2553+ else :
2554+ streaming_response = self .llm .run (
2555+ task = task , * args , ** kwargs
2556+ )
2557+
2558+ if hasattr (streaming_response , "__iter__" ) and not isinstance (streaming_response , str ):
2559+ complete_response = ""
2560+ token_count = 0
2561+ final_chunk = None
2562+ first_chunk = None
2563+
2564+ for chunk in streaming_response :
2565+ if first_chunk is None :
2566+ first_chunk = chunk
2567+
2568+ if hasattr (chunk , "choices" ) and chunk .choices [0 ].delta .content :
2569+ content = chunk .choices [0 ].delta .content
2570+ complete_response += content
2571+ token_count += 1
2572+
2573+ # Schema per token outputted
2574+ token_info = {
2575+ "token_index" : token_count ,
2576+ "model" : getattr (chunk , 'model' , self .get_current_model ()),
2577+ "id" : getattr (chunk , 'id' , '' ),
2578+ "created" : getattr (chunk , 'created' , int (time .time ())),
2579+ "object" : getattr (chunk , 'object' , 'chat.completion.chunk' ),
2580+ "token" : content ,
2581+ "system_fingerprint" : getattr (chunk , 'system_fingerprint' , '' ),
2582+ "finish_reason" : chunk .choices [0 ].finish_reason ,
2583+ "citations" : getattr (chunk , 'citations' , None ),
2584+ "provider_specific_fields" : getattr (chunk , 'provider_specific_fields' , None ),
2585+ "service_tier" : getattr (chunk , 'service_tier' , 'default' ),
2586+ "obfuscation" : getattr (chunk , 'obfuscation' , None ),
2587+ "usage" : getattr (chunk , 'usage' , None ),
2588+ "logprobs" : chunk .choices [0 ].logprobs ,
2589+ "timestamp" : time .time ()
2590+ }
2591+
2592+ print (f"ResponseStream { token_info } " )
2593+
2594+ if streaming_callback is not None :
2595+ streaming_callback (token_info )
2596+
2597+ final_chunk = chunk
2598+
2599+ #Final ModelResponse to stream
2600+ if final_chunk and hasattr (final_chunk , 'usage' ) and final_chunk .usage :
2601+ usage = final_chunk .usage
2602+ print (f"ModelResponseStream(id='{ getattr (final_chunk , 'id' , 'N/A' )} ', "
2603+ f"created={ getattr (final_chunk , 'created' , 'N/A' )} , "
2604+ f"model='{ getattr (final_chunk , 'model' , self .get_current_model ())} ', "
2605+ f"object='{ getattr (final_chunk , 'object' , 'chat.completion.chunk' )} ', "
2606+ f"system_fingerprint='{ getattr (final_chunk , 'system_fingerprint' , 'N/A' )} ', "
2607+ f"choices=[StreamingChoices(finish_reason='{ final_chunk .choices [0 ].finish_reason } ', "
2608+ f"index=0, delta=Delta(provider_specific_fields=None, content=None, role=None, "
2609+ f"function_call=None, tool_calls=None, audio=None), logprobs=None)], "
2610+ f"provider_specific_fields=None, "
2611+ f"usage=Usage(completion_tokens={ usage .completion_tokens } , "
2612+ f"prompt_tokens={ usage .prompt_tokens } , "
2613+ f"total_tokens={ usage .total_tokens } , "
2614+ f"completion_tokens_details=CompletionTokensDetailsWrapper("
2615+ f"accepted_prediction_tokens={ usage .completion_tokens_details .accepted_prediction_tokens } , "
2616+ f"audio_tokens={ usage .completion_tokens_details .audio_tokens } , "
2617+ f"reasoning_tokens={ usage .completion_tokens_details .reasoning_tokens } , "
2618+ f"rejected_prediction_tokens={ usage .completion_tokens_details .rejected_prediction_tokens } , "
2619+ f"text_tokens={ usage .completion_tokens_details .text_tokens } ), "
2620+ f"prompt_tokens_details=PromptTokensDetailsWrapper("
2621+ f"audio_tokens={ usage .prompt_tokens_details .audio_tokens } , "
2622+ f"cached_tokens={ usage .prompt_tokens_details .cached_tokens } , "
2623+ f"text_tokens={ usage .prompt_tokens_details .text_tokens } , "
2624+ f"image_tokens={ usage .prompt_tokens_details .image_tokens } )))" )
2625+ else :
2626+ print (f"ModelResponseStream(id='{ getattr (final_chunk , 'id' , 'N/A' )} ', "
2627+ f"created={ getattr (final_chunk , 'created' , 'N/A' )} , "
2628+ f"model='{ getattr (final_chunk , 'model' , self .get_current_model ())} ', "
2629+ f"object='{ getattr (final_chunk , 'object' , 'chat.completion.chunk' )} ', "
2630+ f"system_fingerprint='{ getattr (final_chunk , 'system_fingerprint' , 'N/A' )} ', "
2631+ f"choices=[StreamingChoices(finish_reason='{ final_chunk .choices [0 ].finish_reason } ', "
2632+ f"index=0, delta=Delta(provider_specific_fields=None, content=None, role=None, "
2633+ f"function_call=None, tool_calls=None, audio=None), logprobs=None)], "
2634+ f"provider_specific_fields=None)" )
2635+
2636+
2637+ self .llm .stream = original_stream
2638+ return complete_response
2639+ else :
2640+ self .llm .stream = original_stream
2641+ return streaming_response
2642+
2643+ elif self .streaming_on and hasattr (self .llm , "stream" ):
25422644 original_stream = self .llm .stream
25432645 self .llm .stream = True
25442646
@@ -3023,6 +3125,8 @@ def pretty_print(self, response: str, loop_count: int):
30233125
30243126 if self .streaming_on :
30253127 pass
3128+ elif self .stream :
3129+ pass
30263130
30273131 if self .print_on :
30283132 formatter .print_panel (
0 commit comments