From 3568519538bfedb56f0c8eaec0f43f31faa63b54 Mon Sep 17 00:00:00 2001 From: Mery-Sanz Date: Tue, 6 May 2025 08:58:22 +0200 Subject: [PATCH] print tool calls in /history --- src/cai/repl/commands/history.py | 81 +++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/src/cai/repl/commands/history.py b/src/cai/repl/commands/history.py index 38eaeb96..f0610f3a 100644 --- a/src/cai/repl/commands/history.py +++ b/src/cai/repl/commands/history.py @@ -2,8 +2,12 @@ History command for CAI REPL. This module provides commands for displaying conversation history. """ +import json +from typing import Any, Dict, List, Optional + from rich.console import Console # pylint: disable=import-error from rich.table import Table # pylint: disable=import-error +from rich.text import Text # pylint: disable=import-error from cai.repl.commands.base import Command, register_command @@ -20,6 +24,20 @@ class HistoryCommand(Command): description="Display the conversation history", aliases=["/h"] ) + + def handle(self, args: Optional[List[str]] = None, + messages: Optional[List[Dict]] = None) -> bool: + """Handle the history command. + + Args: + args: Optional list of command arguments + messages: Optional list of conversation messages + + Returns: + True if the command was handled successfully, False otherwise + """ + # Currently, the history command doesn't take any arguments + return self.handle_no_args() def handle_no_args(self) -> bool: """Handle the command when no arguments are provided. @@ -27,7 +45,7 @@ class HistoryCommand(Command): Returns: True if the command was handled successfully, False otherwise """ - # Access messages directly from repl.py's global scope + # Access messages directly from openai_chatcompletions.py try: from cai.sdk.agents.models.openai_chatcompletions import message_history # pylint: disable=import-outside-toplevel # noqa: E501 except ImportError: @@ -54,10 +72,11 @@ class HistoryCommand(Command): try: role = msg.get("role", "unknown") content = msg.get("content", "") + tool_calls = msg.get("tool_calls", None) - # Truncate long content for better display - if len(content) > 100: - content = content[:97] + "..." + # Create formatted content based on message type + formatted_content = self._format_message_content( + content, tool_calls) # Color the role based on type if role == "user": @@ -74,14 +93,62 @@ class HistoryCommand(Command): table.add_row( str(idx), f"[{role_style}]{role}[/{role_style}]", - content + formatted_content ) - except Exception: - # Si hay un error, evita esto (no agregues la fila) + except Exception as e: + # Log error but continue with next message + console.print(f"[red]Error displaying message {idx}: {e}[/red]") continue console.print(table) return True + + def _format_message_content( + self, content: Any, tool_calls: List[Dict[str, Any]] + ) -> str: + """Format message content for display, handling both text and tool calls. + + Args: + content: Text content of the message + tool_calls: List of tool calls if present + + Returns: + Formatted string representation of the message content + """ + if tool_calls: + # Format tool calls into a readable string + result = [] + for tc in tool_calls: + func_details = tc.get("function", {}) + func_name = func_details.get("name", "unknown_function") + + # Format arguments (pretty-print JSON if possible) + args_str = func_details.get("arguments", "{}") + try: + # Parse and re-format JSON for better readability + args_dict = json.loads(args_str) + args_formatted = json.dumps(args_dict, indent=2) + # Limit to first 100 chars for display + if len(args_formatted) > 100: + args_formatted = args_formatted[:97] + "..." + except (json.JSONDecodeError, TypeError): + # If not valid JSON, use as is + args_formatted = args_str + if len(args_formatted) > 100: + args_formatted = args_formatted[:97] + "..." + + result.append(f"Function: [bold blue]{func_name}[/bold blue]") + result.append(f"Args: {args_formatted}") + + return "\n".join(result) + elif content: + # Regular text content (truncate if too long) + if len(content) > 100: + return content[:97] + "..." + return content + else: + # No content or tool calls (empty message) + return "[dim italic]Empty message[/dim italic]" # Register the command