@@ -437,7 +437,7 @@ def _format_content_safely(
437437 return self ._config .content_formatter (content ), False
438438 return _format_content (content , max_len = self ._config .max_content_length )
439439 except Exception as e :
440- logging .warning (f "Content formatter failed: { e } " )
440+ logging .warning ("Content formatter failed: %s" , e )
441441 return "[FORMATTING FAILED]" , False
442442
443443 async def _ensure_init (self ):
@@ -523,7 +523,21 @@ async def _perform_write(self, row: dict):
523523 self ._write_client .append_rows (iter ([req ]))
524524 ):
525525 if resp .error .code != 0 :
526- logging .error (f"BQ Plugin: Write Error: { resp .error .message } " )
526+ msg = resp .error .message
527+ # Check for common schema mismatch indicators
528+ if (
529+ "schema mismatch" in msg .lower ()
530+ or "field" in msg .lower ()
531+ or "type" in msg .lower ()
532+ ):
533+ logging .error (
534+ "BQ Plugin: Schema Mismatch Error. The BigQuery table schema"
535+ " may be incorrect or out of sync with the plugin. Please"
536+ " verify the table definition. Details: %s" ,
537+ msg ,
538+ )
539+ else :
540+ logging .error ("BQ Plugin: Write Error: %s" , msg )
527541
528542 except RuntimeError as e :
529543 if "Event loop is closed" not in str (e ) and not self ._is_shutting_down :
@@ -578,7 +592,7 @@ async def close(self):
578592
579593 if self ._background_tasks :
580594 logging .info (
581- f "BQ Plugin: Flushing { len ( self . _background_tasks ) } pending logs..."
595+ "BQ Plugin: Flushing %s pending logs..." , len ( self . _background_tasks )
582596 )
583597 try :
584598 await asyncio .wait (
@@ -598,12 +612,12 @@ async def close(self):
598612 timeout = self ._config .client_close_timeout ,
599613 )
600614 except Exception as e :
601- logging .warning (f "BQ Plugin: Error closing write client: { e } " )
615+ logging .warning ("BQ Plugin: Error closing write client: %s" , e )
602616 if self ._bq_client :
603617 try :
604618 self ._bq_client .close ()
605619 except Exception as e :
606- logging .warning (f "BQ Plugin: Error closing BQ client: { e } " )
620+ logging .warning ("BQ Plugin: Error closing BQ client: %s" , e )
607621
608622 self ._write_client = None
609623 self ._bq_client = None
@@ -617,7 +631,14 @@ async def on_user_message_callback(
617631 invocation_context : InvocationContext ,
618632 user_message : types .Content ,
619633 ) -> None :
620- """Callback for user messages."""
634+ """Callback for user messages.
635+
636+ Logs the user message details including:
637+ 1. User content (text)
638+
639+ The content is formatted as 'User Content: {content}'.
640+ If the content length exceeds `max_content_length`, it is truncated.
641+ """
621642 content , truncated = self ._format_content_safely (user_message )
622643 await self ._log ({
623644 "event_type" : "USER_MESSAGE_RECEIVED" ,
@@ -632,7 +653,12 @@ async def on_user_message_callback(
632653 async def before_run_callback (
633654 self , * , invocation_context : InvocationContext
634655 ) -> None :
635- """Callback before agent invocation."""
656+ """Callback before agent invocation.
657+
658+ Logs the start of an agent invocation.
659+ No specific content payload is logged for this event, but standard metadata
660+ (agent name, session ID, invocation ID, user ID) is captured.
661+ """
636662 await self ._log ({
637663 "event_type" : "INVOCATION_STARTING" ,
638664 "agent" : invocation_context .agent .name ,
@@ -644,7 +670,16 @@ async def before_run_callback(
644670 async def on_event_callback (
645671 self , * , invocation_context : InvocationContext , event : Event
646672 ) -> None :
647- """Callback for agent events."""
673+ """Callback for agent events.
674+
675+ Logs generic agent events including:
676+ 1. Event type (determined from event properties)
677+ 2. Event content (text, function calls, or responses)
678+ 3. Error messages (if any)
679+
680+ The content is formatted based on the event type.
681+ If the content length exceeds `max_content_length`, it is truncated.
682+ """
648683 content , truncated = self ._format_content_safely (event .content )
649684 await self ._log ({
650685 "event_type" : _get_event_type (event ),
@@ -661,7 +696,12 @@ async def on_event_callback(
661696 async def after_run_callback (
662697 self , * , invocation_context : InvocationContext
663698 ) -> None :
664- """Callback after agent invocation."""
699+ """Callback after agent invocation.
700+
701+ Logs the completion of an agent invocation.
702+ No specific content payload is logged for this event, but standard metadata
703+ (agent name, session ID, invocation ID, user ID) is captured.
704+ """
665705 await self ._log ({
666706 "event_type" : "INVOCATION_COMPLETED" ,
667707 "agent" : invocation_context .agent .name ,
@@ -673,7 +713,12 @@ async def after_run_callback(
673713 async def before_agent_callback (
674714 self , * , agent : BaseAgent , callback_context : CallbackContext
675715 ) -> None :
676- """Callback before an agent starts."""
716+ """Callback before an agent starts.
717+
718+ Logs the start of a specific agent execution.
719+ Content includes:
720+ 1. Agent Name (from callback context)
721+ """
677722 await self ._log ({
678723 "event_type" : "AGENT_STARTING" ,
679724 "agent" : agent .name ,
@@ -686,7 +731,12 @@ async def before_agent_callback(
686731 async def after_agent_callback (
687732 self , * , agent : BaseAgent , callback_context : CallbackContext
688733 ) -> None :
689- """Callback after an agent completes."""
734+ """Callback after an agent completes.
735+
736+ Logs the completion of a specific agent execution.
737+ Content includes:
738+ 1. Agent Name (from callback context)
739+ """
690740 await self ._log ({
691741 "event_type" : "AGENT_COMPLETED" ,
692742 "agent" : agent .name ,
@@ -699,11 +749,52 @@ async def after_agent_callback(
699749 async def before_model_callback (
700750 self , * , callback_context : CallbackContext , llm_request : LlmRequest
701751 ) -> None :
702- """Callback before LLM call."""
752+ """Callback before LLM call.
753+
754+ Logs the LLM request details including:
755+ 1. Model name
756+ 2. Configuration parameters (temperature, top_p, top_k, max_output_tokens)
757+ 3. Available tool names
758+ 4. Prompt content (user/model messages)
759+ 5. System instructions
760+
761+ The content is formatted as a single string with fields separated by ' | '.
762+ If the total length exceeds `max_content_length`, the string is truncated,
763+ prioritizing the metadata (Model, Params, Tools) over the Prompt and System
764+ Prompt.
765+ """
703766 content_parts = [
704767 f"Model: { llm_request .model or 'default' } " ,
705768 ]
706769 is_truncated = False
770+
771+ # 1. Params
772+ if llm_request .config :
773+ config = llm_request .config
774+ params_to_log = {}
775+ if hasattr (config , "temperature" ) and config .temperature is not None :
776+ params_to_log ["temperature" ] = config .temperature
777+ if hasattr (config , "top_p" ) and config .top_p is not None :
778+ params_to_log ["top_p" ] = config .top_p
779+ if hasattr (config , "top_k" ) and config .top_k is not None :
780+ params_to_log ["top_k" ] = config .top_k
781+ if (
782+ hasattr (config , "max_output_tokens" )
783+ and config .max_output_tokens is not None
784+ ):
785+ params_to_log ["max_output_tokens" ] = config .max_output_tokens
786+
787+ if params_to_log :
788+ params_str = ", " .join ([f"{ k } ={ v } " for k , v in params_to_log .items ()])
789+ content_parts .append (f"Params: {{{ params_str } }}" )
790+
791+ # 2. Tools
792+ if llm_request .tools_dict :
793+ content_parts .append (
794+ f"Available Tools: { list (llm_request .tools_dict .keys ())} "
795+ )
796+
797+ # 3. Prompt
707798 if contents := getattr (llm_request , "contents" , None ):
708799 prompt_parts = []
709800 for c in contents :
@@ -713,6 +804,8 @@ async def before_model_callback(
713804 is_truncated = True
714805 prompt_str = " | " .join (prompt_parts )
715806 content_parts .append (f"Prompt: { prompt_str } " )
807+
808+ # 4. System Prompt
716809 system_instruction_text = "None"
717810 if llm_request .config and llm_request .config .system_instruction :
718811 si = llm_request .config .system_instruction
@@ -736,29 +829,6 @@ async def before_model_callback(
736829 system_instruction_text = "Empty"
737830
738831 content_parts .append (f"System Prompt: { system_instruction_text } " )
739- if llm_request .config :
740- config = llm_request .config
741- params_to_log = {}
742- if hasattr (config , "temperature" ) and config .temperature is not None :
743- params_to_log ["temperature" ] = config .temperature
744- if hasattr (config , "top_p" ) and config .top_p is not None :
745- params_to_log ["top_p" ] = config .top_p
746- if hasattr (config , "top_k" ) and config .top_k is not None :
747- params_to_log ["top_k" ] = config .top_k
748- if (
749- hasattr (config , "max_output_tokens" )
750- and config .max_output_tokens is not None
751- ):
752- params_to_log ["max_output_tokens" ] = config .max_output_tokens
753-
754- if params_to_log :
755- params_str = ", " .join ([f"{ k } ={ v } " for k , v in params_to_log .items ()])
756- content_parts .append (f"Params: {{{ params_str } }}" )
757-
758- if llm_request .tools_dict :
759- content_parts .append (
760- f"Available Tools: { list (llm_request .tools_dict .keys ())} "
761- )
762832
763833 final_content = " | " .join (content_parts )
764834 max_len = self ._config .max_content_length
@@ -778,7 +848,16 @@ async def before_model_callback(
778848 async def after_model_callback (
779849 self , * , callback_context : CallbackContext , llm_response : LlmResponse
780850 ) -> None :
781- """Callback after LLM call."""
851+ """Callback after LLM call.
852+
853+ Logs the LLM response details including:
854+ 1. Tool calls (if any)
855+ 2. Text response (if no tool calls)
856+ 3. Token usage statistics (prompt, candidates, total)
857+
858+ The content is formatted as a single string with fields separated by ' | '.
859+ If the content length exceeds `max_content_length`, it is truncated.
860+ """
782861 content_parts = []
783862 content = llm_response .content
784863 is_tool_call = False
@@ -838,7 +917,17 @@ async def before_tool_callback(
838917 tool_args : dict [str , Any ],
839918 tool_context : ToolContext ,
840919 ) -> None :
841- """Callback before tool call."""
920+ """Callback before tool call.
921+
922+ Logs the tool execution start details including:
923+ 1. Tool name
924+ 2. Tool description
925+ 3. Tool arguments
926+
927+ The content is formatted as 'Tool Name: ..., Description: ..., Arguments:
928+ ...'.
929+ If the content length exceeds `max_content_length`, it is truncated.
930+ """
842931 args_str , truncated = _format_args (
843932 tool_args , max_len = self ._config .max_content_length
844933 )
@@ -867,7 +956,15 @@ async def after_tool_callback(
867956 tool_context : ToolContext ,
868957 result : dict [str , Any ],
869958 ) -> None :
870- """Callback after tool call."""
959+ """Callback after tool call.
960+
961+ Logs the tool execution result details including:
962+ 1. Tool name
963+ 2. Tool result
964+
965+ The content is formatted as 'Tool Name: ..., Result: ...'.
966+ If the content length exceeds `max_content_length`, it is truncated.
967+ """
871968 result_str , truncated = _format_args (
872969 result , max_len = self ._config .max_content_length
873970 )
@@ -892,7 +989,12 @@ async def on_model_error_callback(
892989 llm_request : LlmRequest ,
893990 error : Exception ,
894991 ) -> None :
895- """Callback for LLM errors."""
992+ """Callback for model errors.
993+
994+ Logs errors that occur during LLM calls.
995+ No specific content payload is logged, but the error message is captured
996+ in the `error_message` field.
997+ """
896998 await self ._log ({
897999 "event_type" : "LLM_ERROR" ,
8981000 "agent" : callback_context .agent_name ,
@@ -910,7 +1012,16 @@ async def on_tool_error_callback(
9101012 tool_context : ToolContext ,
9111013 error : Exception ,
9121014 ) -> None :
913- """Callback for tool errors."""
1015+ """Callback for tool errors.
1016+
1017+ Logs errors that occur during tool execution.
1018+ Content includes:
1019+ 1. Tool name
1020+ 2. Tool arguments
1021+
1022+ The error message is captured in the `error_message` field.
1023+ If the content length exceeds `max_content_length`, it is truncated.
1024+ """
9141025 args_str , truncated = _format_args (
9151026 tool_args , max_len = self ._config .max_content_length
9161027 )
0 commit comments