diff --git a/src/cai/tools/common.py b/src/cai/tools/common.py index b8042032..ba99dd04 100644 --- a/src/cai/tools/common.py +++ b/src/cai/tools/common.py @@ -305,15 +305,21 @@ def _run_local_streamed(command, call_id, timeout=100, tool_name=None): cmd = parts[0] if parts else "" args = parts[1] if len(parts) > 1 else "" + # Format clean arguments, following the same rules as cli_print_tool_output + arg_parts = [] + if cmd: + arg_parts.append(f"command={cmd}") + if args and args.strip(): # Only add args if non-empty + arg_parts.append(f"args={args}") + args_str = ", ".join(arg_parts) + header = Text() header.append(tool_name, style="#00BCD4") header.append("(", style="yellow") - # Format to match: tool_name({"command":"ls","args":"-la","ctf":{},"async_mode":false,"session_id":""}) - header.append(f'{{"command":"{cmd}","args":"{args}","ctf":{{}},"async_mode":false,"session_id":""}}', style="yellow") + header.append(args_str, style="yellow") header.append(")", style="yellow") content = Text() - content.append(f"Executing: {command}\n\n", style="green") panel = Panel( Text.assemble(header, "\n\n", content), @@ -367,12 +373,9 @@ def _run_local_streamed(command, call_id, timeout=100, tool_name=None): live.update(panel) # Add completion message - completion_status = "Completed" if return_code == 0 else f"Failed (code {return_code})" - content.append(f"\nCommand {completion_status}", style="green") panel = Panel( Text.assemble(header, "\n\n", content), title="[bold green]Tool Execution[/bold green]", - subtitle=f"[bold green]{completion_status}[/bold green]", border_style="green", padding=(1, 2), box=ROUNDED @@ -387,7 +390,14 @@ def _run_local_streamed(command, call_id, timeout=100, tool_name=None): parts = command.strip().split(' ', 1) cmd = parts[0] if parts else "" args = parts[1] if len(parts) > 1 else "" - tool_args = {"command": cmd, "args": args, "ctf": {}, "async_mode": False, "session_id": ""} + + # Create a dictionary with only non-empty values (following the same rules) + tool_args = {} + if cmd: + tool_args["command"] = cmd + if args and args.strip(): + tool_args["args"] = args + # Note: Omitted empty values and async_mode=False as it's default # Initial notification - just once cli_print_tool_output(tool_name, tool_args, "Command started...", call_id=call_id) diff --git a/src/cai/util.py b/src/cai/util.py index 0736add3..de87137c 100644 --- a/src/cai/util.py +++ b/src/cai/util.py @@ -1125,9 +1125,33 @@ def cli_print_tool_output(tool_name="", args="", output="", call_id=None, execut # Create a console for output console = Console() - # Format arguments as a string if they are a dictionary + # Format arguments for display + # Parse JSON string if args is a string + if isinstance(args, str) and args.strip().startswith('{'): + try: + import json + args = json.loads(args) + except: + # Keep as is if not valid JSON + pass + + # Format arguments as a clean string if isinstance(args, dict): - args_str = ", ".join([f"{key}='{value}'" for key, value in args.items()]) + # Only include non-empty values and exclude async_mode=false + arg_parts = [] + for key, value in args.items(): + # Skip empty values + if value == "" or value == {} or value is None: + continue + # Skip async_mode=false (default) + if key == "async_mode" and value is False: + continue + # Format the value + if isinstance(value, str): + arg_parts.append(f"{key}={value}") + else: + arg_parts.append(f"{key}={value}") + args_str = ", ".join(arg_parts) else: args_str = str(args) @@ -1213,38 +1237,36 @@ def cli_print_tool_output(tool_name="", args="", output="", call_id=None, execut except ImportError: # Fall back to simple formatting if Rich is not available - # Format arguments as a string if they are a dictionary + # Format arguments in the cleaner format + # Parse JSON string if args is a string + if isinstance(args, str) and args.strip().startswith('{'): + try: + import json + args = json.loads(args) + except: + # Keep as is if not valid JSON + pass + + # Format arguments as a clean string if isinstance(args, dict): - args_str = ", ".join([f"{key}='{value}'" for key, value in args.items()]) + # Only include non-empty values and exclude async_mode=false + arg_parts = [] + for key, value in args.items(): + # Skip empty values + if value == "" or value == {} or value is None: + continue + # Skip async_mode=false (default) + if key == "async_mode" and value is False: + continue + # Format the value + if isinstance(value, str): + arg_parts.append(f"{key}={value}") + else: + arg_parts.append(f"{key}={value}") + args_str = ", ".join(arg_parts) else: args_str = str(args) - # Simplify output presentation for streaming mode - if call_id: - # This is a streaming update, so we need to overwrite previous output - # We'll use a basic format that's better suited for streaming - - # Get terminal width for better formatting - try: - term_width = os.get_terminal_size().columns - except: # pylint: disable=bare-except - term_width = 80 - - # Create a header for the tool output - header = f"{tool_name}({args_str})" - header = header[:term_width-4] - - # Clear the screen for the tool output (alternative approach) - print(f"\r{header}") - - # Print the content - # For streaming updates, we'll use a simple format - print(output) - - # Force flush to ensure output is displayed immediately - sys.stdout.flush() - return - # For non-streaming output, use the original formatting tool_call = f"{tool_name}({args_str})"