diff --git a/adalflow/adalflow/components/agent/react.py b/adalflow/adalflow/components/agent/react.py index de4a8a12..fe571051 100644 --- a/adalflow/adalflow/components/agent/react.py +++ b/adalflow/adalflow/components/agent/react.py @@ -9,7 +9,7 @@ from adalflow.core.generator import Generator -from adalflow.optim.grad_component import GradComponent +from adalflow.optim.grad_component import GradComponent2 from adalflow.optim.parameter import Parameter, ParameterType from adalflow.core.func_tool import FunctionTool, AsyncCallable from adalflow.core.tool_manager import ToolManager @@ -130,11 +130,9 @@ def map_step_history_list_to_prompt(x: Parameter) -> str: return "\n".join(output) -class AppendStepHistory(GradComponent): +class AppendStepHistory(GradComponent2): def __init__(self): - super().__init__() - self.name = "AppendStepHistory" - self._component_desc = "Append the step_output to the step_history." + super().__init__(desc="Append the step_output to the step_history.") def call( self, step_output: StepOutput, step_history: List[StepOutput] @@ -154,11 +152,9 @@ def forward(self, *args, **kwargs) -> Parameter: return output -class FunctionOutputToStepOutput(GradComponent): +class FunctionOutputToStepOutput(GradComponent2): def __init__(self): - super().__init__() - self.name = "FunctionOutputToStepOutput" - self._component_desc = "Convert the FunctionOutput to StepOutput" + super().__init__(desc="Convert the FunctionOutput to StepOutput") def call( self, @@ -368,7 +364,7 @@ def set_step_output_with_error( step_output: StepOutput, error: str, response: Any ): """Set the step_output with error.""" - step_output.observation = f"erro: {error} at {response.data}" + step_output.observation = f"error: {error} at {response.data}" return step_output response.add_successor_map_fn( @@ -418,7 +414,6 @@ def set_step_output_with_error( return handle_error(response, e) try: - # printc(f"func: {func}", color="yellow") # replace the id if isinstance(func, Parameter): @@ -497,7 +492,7 @@ def _execute_action_eval_mode( id=None, ) -> StepOutput: """Execute the action and update the step_output.""" - if x.error: + if x.error or not x.data: error_msg = f"Error planning step {step}: {x.error}" step_output.observation = error_msg step_output.action = None @@ -506,6 +501,7 @@ def _execute_action_eval_mode( else: try: fun_expr: FunctionExpression = x.data + printc(f"Step {step}: {fun_expr}", color="blue") step_output.action = fun_expr log.debug(f"Step {step}: {fun_expr}") diff --git a/adalflow/adalflow/core/func_tool.py b/adalflow/adalflow/core/func_tool.py index 6524ad7d..419ae846 100644 --- a/adalflow/adalflow/core/func_tool.py +++ b/adalflow/adalflow/core/func_tool.py @@ -18,7 +18,7 @@ ) from adalflow.core import Component from adalflow.optim.parameter import Parameter -from adalflow.optim.grad_component import GradComponent +from adalflow.optim.grad_component import GradComponent2 from adalflow.core.functional import ( get_fun_schema, ) @@ -59,7 +59,7 @@ def find_instance_name_from_self(instance): # TODO: improve the support for async functions, similarly a component might be used as a tool -class FunctionTool(GradComponent): +class FunctionTool(GradComponent2): __doc__ = r"""Describing and executing a function via call with arguments. @@ -116,7 +116,9 @@ def __init__( component: Optional[Component] = None, definition: Optional[FunctionDefinition] = None, ): - super().__init__() + super().__init__( + name="FunctionTool", desc="A component calls and executes a function." + ) nest_asyncio.apply() assert fn is not None, "fn must be provided" diff --git a/adalflow/adalflow/core/tool_manager.py b/adalflow/adalflow/core/tool_manager.py index 340fbfbb..caf5137a 100644 --- a/adalflow/adalflow/core/tool_manager.py +++ b/adalflow/adalflow/core/tool_manager.py @@ -21,7 +21,7 @@ import warnings from adalflow.core.container import ComponentList -from adalflow.optim.grad_component import GradComponent +from adalflow.optim.grad_component import GradComponent2 from adalflow.core.component import Component from adalflow.core.func_tool import FunctionTool from adalflow.core.types import ( @@ -107,9 +107,9 @@ def dummy_pass_through_for_untrainable_fn(output, func): return output -class FunctionExperssionToFunction(GradComponent): +class FunctionExperssionToFunction(GradComponent2): def __init__(self): - super().__init__() + super().__init__(desc="Convert FunctionExpression to Function") def call(self, expr: FunctionExpression, context: Dict[str, object]) -> Function: @@ -227,21 +227,21 @@ def parse_func_expr( r"""Parse the function call expression.""" if isinstance(expr, Parameter): - try: + # try: - func = FunctionExperssionToFunction() - expr.add_successor_map_fn(func, map_fn=map_fn) - # print("FunctionExperssionToFunction") - output = func.forward(expr, context=self.context) - # print(f"output data: {output.data}") - return output + func = FunctionExperssionToFunction() + expr.add_successor_map_fn(func, map_fn=map_fn) + # print("FunctionExperssionToFunction") + output = func.forward(expr, context=self.context) + # print(f"output data: {output.data}") + return output - except Exception as e: - error_msg = ( - f"Error {e} parsing function call expression: {map_fn(expr)}" - ) - return error_msg - else: + # except Exception as e: + # error_msg = ( + # f"Error {e} parsing function call expression: {map_fn(expr)}" + # ) + # return error_msg + # else: try: expr_str = expr.action func_name, args, kwargs = parse_function_call_expr( @@ -278,6 +278,7 @@ def call( expr_or_fun: Union[FunctionExpression, Function], step: Literal["execute"] = "execute", ) -> Union[FunctionOutput, Function, Parameter]: + print(f"self.training: {self.training}, expr_or_fun: {expr_or_fun}") if not isinstance(expr_or_fun, (Function, FunctionExpression)): raise ValueError( f"expr_or_fun should be either a Function or FunctionExpression. Got {expr_or_fun}" diff --git a/adalflow/adalflow/optim/grad_component.py b/adalflow/adalflow/optim/grad_component.py index bef0ba2d..92d3a56c 100644 --- a/adalflow/adalflow/optim/grad_component.py +++ b/adalflow/adalflow/optim/grad_component.py @@ -323,8 +323,8 @@ class GradComponent2(GradComponent): def __init__( self, - name: str, desc: str, + name: Optional[str] = None, backward_engine: Optional["BackwardEngine"] = None, model_client: "ModelClient" = None, model_kwargs: Dict[str, object] = None, @@ -532,7 +532,8 @@ def backward(self, *, response: "OutputParameter", id: str = None, **kwargs): for pred in children_params: pred.backward_engine_disabled = True - if not self.backward_engine: + # use pass through gradient when there is one predecessor + if not self.backward_engine or len(children_params) < 2: super().backward(response=response, id=id) else: @@ -540,7 +541,7 @@ def backward(self, *, response: "OutputParameter", id: str = None, **kwargs): for _, pred in enumerate(children_params): if response.score is not None: pred.set_score(response.score) - printc(f"score score for pred name: {pred.name}") + printc(f"score {response.score} for pred name: {pred.name}") if not pred.requires_opt: continue diff --git a/adalflow/adalflow/optim/parameter.py b/adalflow/adalflow/optim/parameter.py index 4b7093e6..69142f13 100644 --- a/adalflow/adalflow/optim/parameter.py +++ b/adalflow/adalflow/optim/parameter.py @@ -22,6 +22,8 @@ from adalflow.optim.types import ParameterType from adalflow.core.base_data_class import DataClass from adalflow.utils.logger import printc +import html + if TYPE_CHECKING: from adalflow.optim.text_grad.tgd_optimizer import TGDData, TGDOptimizerTrace @@ -1229,19 +1231,29 @@ def draw_output_subgraph( node_ids = set() for node in nodes: + escaped_name = html.escape(node.name if node.name else "") + escaped_param_type = html.escape( + node.param_type.name if node.param_type else "" + ) + escaped_value = html.escape( + node.get_short_value() if node.get_short_value() else "" + ) + node_label = f"""
Name: | {node.name} |
Type: | {node.param_type} |
Value: | {node.get_short_value()} |
Name: | {escaped_name} |
Type: | {escaped_param_type} |
Value: | {escaped_value} |
Component Trace ID: | {node.component_trace.id} |
Component Trace ID: | {escaped_ct_id} |
Component Trace Name: | {node.component_trace.name} |
Component Trace Name: | {escaped_ct_name} |