[docs]deftry_json_stringify(obj:Any,fallback:str)->str:"""Try to stringify an object to JSON. Args: obj: Object to stringify. fallback: Fallback string to return if the object cannot be stringified. Returns: A JSON string if the object can be stringified, otherwise the fallback string. """try:returnjson.dumps(obj,indent=2,ensure_ascii=False)exceptException:returnfallback
[docs]defelapsed(run:Any)->str:"""Get the elapsed time of a run. Args: run: any object with a start_time and end_time attribute. Returns: A string with the elapsed time in seconds or milliseconds if time is less than a second. """elapsed_time=run.end_time-run.start_timemilliseconds=elapsed_time.total_seconds()*1000ifmilliseconds<1000:returnf"{milliseconds:.0f}ms"returnf"{(milliseconds/1000):.2f}s"
[docs]classFunctionCallbackHandler(BaseTracer):"""Tracer that calls a function with a single str parameter."""name:str="function_callback_handler""""The name of the tracer. This is used to identify the tracer in the logs. Default is "function_callback_handler"."""
[docs]defget_parents(self,run:Run)->list[Run]:"""Get the parents of a run. Args: run: The run to get the parents of. Returns: A list of parent runs. """parents=[]current_run=runwhilecurrent_run.parent_run_id:parent=self.run_map.get(str(current_run.parent_run_id))ifparent:parents.append(parent)current_run=parentelse:breakreturnparents
[docs]defget_breadcrumbs(self,run:Run)->str:"""Get the breadcrumbs of a run. Args: run: The run to get the breadcrumbs of. Returns: A string with the breadcrumbs of the run. """parents=self.get_parents(run)[::-1]string=" > ".join(f"{parent.run_type}:{parent.name}"ifi!=len(parents)-1elsef"{parent.run_type}:{parent.name}"fori,parentinenumerate(parents+[run]))returnstring
# logging methodsdef_on_chain_start(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)run_type=run.run_type.capitalize()self.function_callback(f"{get_colored_text('[chain/start]',color='green')} "+get_bolded_text(f"[{crumbs}] Entering {run_type} run with input:\n")+f"{try_json_stringify(run.inputs,'[inputs]')}")def_on_chain_end(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)run_type=run.run_type.capitalize()self.function_callback(f"{get_colored_text('[chain/end]',color='blue')} "+get_bolded_text(f"[{crumbs}] [{elapsed(run)}] Exiting {run_type} run with output:\n")+f"{try_json_stringify(run.outputs,'[outputs]')}")def_on_chain_error(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)run_type=run.run_type.capitalize()self.function_callback(f"{get_colored_text('[chain/error]',color='red')} "+get_bolded_text(f"[{crumbs}] [{elapsed(run)}] {run_type} run errored with error:\n")+f"{try_json_stringify(run.error,'[error]')}")def_on_llm_start(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)inputs=({"prompts":[p.strip()forpinrun.inputs["prompts"]]}if"prompts"inrun.inputselserun.inputs)self.function_callback(f"{get_colored_text('[llm/start]',color='green')} "+get_bolded_text(f"[{crumbs}] Entering LLM run with input:\n")+f"{try_json_stringify(inputs,'[inputs]')}")def_on_llm_end(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)self.function_callback(f"{get_colored_text('[llm/end]',color='blue')} "+get_bolded_text(f"[{crumbs}] [{elapsed(run)}] Exiting LLM run with output:\n")+f"{try_json_stringify(run.outputs,'[response]')}")def_on_llm_error(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)self.function_callback(f"{get_colored_text('[llm/error]',color='red')} "+get_bolded_text(f"[{crumbs}] [{elapsed(run)}] LLM run errored with error:\n")+f"{try_json_stringify(run.error,'[error]')}")def_on_tool_start(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)self.function_callback(f"{get_colored_text('[tool/start]',color='green')} "+get_bolded_text(f"[{crumbs}] Entering Tool run with input:\n")+f'"{run.inputs["input"].strip()}"')def_on_tool_end(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)ifrun.outputs:self.function_callback(f"{get_colored_text('[tool/end]',color='blue')} "+get_bolded_text(f"[{crumbs}] [{elapsed(run)}] Exiting Tool run with output:\n")+f'"{str(run.outputs["output"]).strip()}"')def_on_tool_error(self,run:Run)->None:crumbs=self.get_breadcrumbs(run)self.function_callback(f"{get_colored_text('[tool/error]',color='red')} "+get_bolded_text(f"[{crumbs}] [{elapsed(run)}] ")+f"Tool run errored with error:\n"f"{run.error}")
[docs]classConsoleCallbackHandler(FunctionCallbackHandler):"""Tracer that prints to the console."""name:str="console_callback_handler"