@@ -218,7 +218,8 @@ class Agent:
218218 preset_stopping_token (bool): Enable preset stopping token
219219 traceback (Any): The traceback
220220 traceback_handlers (Any): The traceback handlers
221- streaming_on (bool): Enable streaming
221+ streaming_on (bool): Enable basic streaming with formatted panels
222+ stream (bool): Enable detailed token-by-token streaming with metadata (citations, tokens used, etc.)
222223 docs (List[str]): The list of documents
223224 docs_folder (str): The folder containing the documents
224225 verbose (bool): Enable verbose mode
@@ -310,9 +311,9 @@ class Agent:
310311 >>> print(response)
311312 >>> # Generate a report on the financials.
312313
313- >>> # Real-time streaming example
314- >>> agent = Agent(model_name="gpt-4.1", max_loops=1, streaming_on =True)
315- >>> response = agent.run("Tell me a long story.") # Will stream in real-time
314+ >>> # Detailed token streaming example
315+ >>> agent = Agent(model_name="gpt-4.1", max_loops=1, stream =True)
316+ >>> response = agent.run("Tell me a story.") # Will stream each token with detailed metadata
316317 >>> print(response) # Final complete response
317318
318319 >>> # Fallback model example
@@ -366,6 +367,7 @@ def __init__(
366367 traceback : Optional [Any ] = None ,
367368 traceback_handlers : Optional [Any ] = None ,
368369 streaming_on : Optional [bool ] = False ,
370+ stream : Optional [bool ] = False ,
369371 docs : List [str ] = None ,
370372 docs_folder : Optional [str ] = None ,
371373 verbose : Optional [bool ] = False ,
@@ -516,6 +518,7 @@ def __init__(
516518 self .traceback = traceback
517519 self .traceback_handlers = traceback_handlers
518520 self .streaming_on = streaming_on
521+ self .stream = stream
519522 self .docs = docs
520523 self .docs_folder = docs_folder
521524 self .verbose = verbose
@@ -1346,6 +1349,8 @@ def _run(
13461349 )
13471350 elif self .streaming_on :
13481351 pass
1352+ elif self .stream :
1353+ pass
13491354 else :
13501355 self .pretty_print (
13511356 response , loop_count
@@ -2566,8 +2571,105 @@ def call_llm(
25662571 del kwargs ["is_last" ]
25672572
25682573 try :
2569- # Set streaming parameter in LLM if streaming is enabled
2570- if self .streaming_on and hasattr (self .llm , "stream" ):
2574+ if self .stream and hasattr (self .llm , "stream" ):
2575+ original_stream = self .llm .stream
2576+ self .llm .stream = True
2577+
2578+ if img is not None :
2579+ streaming_response = self .llm .run (
2580+ task = task , img = img , * args , ** kwargs
2581+ )
2582+ else :
2583+ streaming_response = self .llm .run (
2584+ task = task , * args , ** kwargs
2585+ )
2586+
2587+ if hasattr (streaming_response , "__iter__" ) and not isinstance (streaming_response , str ):
2588+ complete_response = ""
2589+ token_count = 0
2590+ final_chunk = None
2591+ first_chunk = None
2592+
2593+ for chunk in streaming_response :
2594+ if first_chunk is None :
2595+ first_chunk = chunk
2596+
2597+ if hasattr (chunk , "choices" ) and chunk .choices [0 ].delta .content :
2598+ content = chunk .choices [0 ].delta .content
2599+ complete_response += content
2600+ token_count += 1
2601+
2602+ # Schema per token outputted
2603+ token_info = {
2604+ "token_index" : token_count ,
2605+ "model" : getattr (chunk , 'model' , self .get_current_model ()),
2606+ "id" : getattr (chunk , 'id' , '' ),
2607+ "created" : getattr (chunk , 'created' , int (time .time ())),
2608+ "object" : getattr (chunk , 'object' , 'chat.completion.chunk' ),
2609+ "token" : content ,
2610+ "system_fingerprint" : getattr (chunk , 'system_fingerprint' , '' ),
2611+ "finish_reason" : chunk .choices [0 ].finish_reason ,
2612+ "citations" : getattr (chunk , 'citations' , None ),
2613+ "provider_specific_fields" : getattr (chunk , 'provider_specific_fields' , None ),
2614+ "service_tier" : getattr (chunk , 'service_tier' , 'default' ),
2615+ "obfuscation" : getattr (chunk , 'obfuscation' , None ),
2616+ "usage" : getattr (chunk , 'usage' , None ),
2617+ "logprobs" : chunk .choices [0 ].logprobs ,
2618+ "timestamp" : time .time ()
2619+ }
2620+
2621+ print (f"ResponseStream { token_info } " )
2622+
2623+ if streaming_callback is not None :
2624+ streaming_callback (token_info )
2625+
2626+ final_chunk = chunk
2627+
2628+ #Final ModelResponse to stream
2629+ if final_chunk and hasattr (final_chunk , 'usage' ) and final_chunk .usage :
2630+ usage = final_chunk .usage
2631+ print (f"ModelResponseStream(id='{ getattr (final_chunk , 'id' , 'N/A' )} ', "
2632+ f"created={ getattr (final_chunk , 'created' , 'N/A' )} , "
2633+ f"model='{ getattr (final_chunk , 'model' , self .get_current_model ())} ', "
2634+ f"object='{ getattr (final_chunk , 'object' , 'chat.completion.chunk' )} ', "
2635+ f"system_fingerprint='{ getattr (final_chunk , 'system_fingerprint' , 'N/A' )} ', "
2636+ f"choices=[StreamingChoices(finish_reason='{ final_chunk .choices [0 ].finish_reason } ', "
2637+ f"index=0, delta=Delta(provider_specific_fields=None, content=None, role=None, "
2638+ f"function_call=None, tool_calls=None, audio=None), logprobs=None)], "
2639+ f"provider_specific_fields=None, "
2640+ f"usage=Usage(completion_tokens={ usage .completion_tokens } , "
2641+ f"prompt_tokens={ usage .prompt_tokens } , "
2642+ f"total_tokens={ usage .total_tokens } , "
2643+ f"completion_tokens_details=CompletionTokensDetailsWrapper("
2644+ f"accepted_prediction_tokens={ usage .completion_tokens_details .accepted_prediction_tokens } , "
2645+ f"audio_tokens={ usage .completion_tokens_details .audio_tokens } , "
2646+ f"reasoning_tokens={ usage .completion_tokens_details .reasoning_tokens } , "
2647+ f"rejected_prediction_tokens={ usage .completion_tokens_details .rejected_prediction_tokens } , "
2648+ f"text_tokens={ usage .completion_tokens_details .text_tokens } ), "
2649+ f"prompt_tokens_details=PromptTokensDetailsWrapper("
2650+ f"audio_tokens={ usage .prompt_tokens_details .audio_tokens } , "
2651+ f"cached_tokens={ usage .prompt_tokens_details .cached_tokens } , "
2652+ f"text_tokens={ usage .prompt_tokens_details .text_tokens } , "
2653+ f"image_tokens={ usage .prompt_tokens_details .image_tokens } )))" )
2654+ else :
2655+ print (f"ModelResponseStream(id='{ getattr (final_chunk , 'id' , 'N/A' )} ', "
2656+ f"created={ getattr (final_chunk , 'created' , 'N/A' )} , "
2657+ f"model='{ getattr (final_chunk , 'model' , self .get_current_model ())} ', "
2658+ f"object='{ getattr (final_chunk , 'object' , 'chat.completion.chunk' )} ', "
2659+ f"system_fingerprint='{ getattr (final_chunk , 'system_fingerprint' , 'N/A' )} ', "
2660+ f"choices=[StreamingChoices(finish_reason='{ final_chunk .choices [0 ].finish_reason } ', "
2661+ f"index=0, delta=Delta(provider_specific_fields=None, content=None, role=None, "
2662+ f"function_call=None, tool_calls=None, audio=None), logprobs=None)], "
2663+ f"provider_specific_fields=None)" )
2664+
2665+
2666+ self .llm .stream = original_stream
2667+ return complete_response
2668+ else :
2669+ self .llm .stream = original_stream
2670+ return streaming_response
2671+
2672+ elif self .streaming_on and hasattr (self .llm , "stream" ):
25712673 original_stream = self .llm .stream
25722674 self .llm .stream = True
25732675
@@ -3052,6 +3154,8 @@ def pretty_print(self, response: str, loop_count: int):
30523154
30533155 if self .streaming_on :
30543156 pass
3157+ elif self .stream :
3158+ pass
30553159
30563160 if self .print_on :
30573161 formatter .print_panel (
0 commit comments