mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 16:18:30 +00:00
* WIP * WIP * wip * wip * WIP * More WIP * Its working but needs a massive clean up * output type works now * Usage metrics fixed * more testing * WIP * cleaning up * Update logger * 99% done. Need to make docs match new example * cleanup * drop hard coded examples * docs * Clean up * Fix errors * Trying to fix CI issues * more type checker fixes * More type checking fixes * Update LiteAgent documentation for clarity and consistency; replace WebsiteSearchTool with SerperDevTool, and improve formatting in examples. * fix fingerprinting issues * fix type-checker * Fix type-checker issue by adding type ignore comment for cache read in ToolUsage class * Add optional agent parameter to CrewAgentParser and enhance action handling logic * Remove unused parameters from ToolUsage instantiation in tests and clean up debug print statement in CrewAgentParser. * Remove deprecated test files and examples for LiteAgent; add comprehensive tests for LiteAgent functionality, including tool usage and structured output handling. * Remove unused variable 'result' from ToolUsage class to clean up code. * Add initialization for 'result' variable in ToolUsage class to resolve type-checker warnings * Refactor agent_utils.py by removing unused event imports and adding missing commas in function definitions. Update test_events.py to reflect changes in expected event counts and adjust assertions accordingly. Modify test_tools_emits_error_events.yaml to include new headers and update response content for consistency with recent API changes. * Enhance tests in crew_test.py by verifying cache behavior in test_tools_with_custom_caching and ensuring proper agent initialization with added commas in test_crew_kickoff_for_each_works_with_manager_agent_copy. * Update agent tests to reflect changes in expected call counts and improve response formatting in YAML cassette. Adjusted mock call count from 2 to 3 and refined interaction formats for clarity and consistency. * Refactor agent tests to update model versions and improve response formatting in YAML cassettes. Changed model references from 'o1-preview' to 'o3-mini' and adjusted interaction formats for consistency. Enhanced error handling in context length tests and refined mock setups for better clarity. * Update tool usage logging to ensure tool arguments are consistently formatted as strings. Adjust agent test cases to reflect changes in maximum iterations and expected outputs, enhancing clarity in assertions. Update YAML cassettes to align with new response formats and improve overall consistency across tests. * Update YAML cassette for LLM tests to reflect changes in response structure and model version. Adjusted request and response headers, including updated content length and user agent. Enhanced token limits and request counts for improved testing accuracy. * Update tool usage logging to store tool arguments as native types instead of strings, enhancing data integrity and usability. * Refactor agent tests by removing outdated test cases and updating YAML cassettes to reflect changes in tool usage and response formats. Adjusted request and response headers, including user agent and content length, for improved accuracy in testing. Enhanced interaction formats for consistency across tests. * Add Excalidraw diagram file for visual representation of input-output flow Created a new Excalidraw file that includes a diagram illustrating the input box, database, and output box with connecting arrows. This visual aid enhances understanding of the data flow within the application. * Remove redundant error handling for action and final answer in CrewAgentParser. Update tests to reflect this change by deleting the corresponding test case. --------- Co-authored-by: Lorenze Jay <63378463+lorenzejay@users.noreply.github.com> Co-authored-by: Lorenze Jay <lorenzejaytech@gmail.com>
786 lines
27 KiB
Python
786 lines
27 KiB
Python
from typing import Any, Dict, Optional
|
|
|
|
from rich.console import Console
|
|
from rich.panel import Panel
|
|
from rich.text import Text
|
|
from rich.tree import Tree
|
|
|
|
|
|
class ConsoleFormatter:
|
|
current_crew_tree: Optional[Tree] = None
|
|
current_task_branch: Optional[Tree] = None
|
|
current_agent_branch: Optional[Tree] = None
|
|
current_tool_branch: Optional[Tree] = None
|
|
current_flow_tree: Optional[Tree] = None
|
|
current_method_branch: Optional[Tree] = None
|
|
current_lite_agent_branch: Optional[Tree] = None
|
|
tool_usage_counts: Dict[str, int] = {}
|
|
|
|
def __init__(self, verbose: bool = False):
|
|
self.console = Console(width=None)
|
|
self.verbose = verbose
|
|
|
|
def create_panel(self, content: Text, title: str, style: str = "blue") -> Panel:
|
|
"""Create a standardized panel with consistent styling."""
|
|
return Panel(
|
|
content,
|
|
title=title,
|
|
border_style=style,
|
|
padding=(1, 2),
|
|
)
|
|
|
|
def create_status_content(
|
|
self, title: str, name: str, status_style: str = "blue", **fields
|
|
) -> Text:
|
|
"""Create standardized status content with consistent formatting."""
|
|
content = Text()
|
|
content.append(f"{title}\n", style=f"{status_style} bold")
|
|
content.append("Name: ", style="white")
|
|
content.append(f"{name}\n", style=status_style)
|
|
|
|
for label, value in fields.items():
|
|
content.append(f"{label}: ", style="white")
|
|
content.append(
|
|
f"{value}\n", style=fields.get(f"{label}_style", status_style)
|
|
)
|
|
|
|
return content
|
|
|
|
def update_tree_label(
|
|
self,
|
|
tree: Tree,
|
|
prefix: str,
|
|
name: str,
|
|
style: str = "blue",
|
|
status: Optional[str] = None,
|
|
) -> None:
|
|
"""Update tree label with consistent formatting."""
|
|
label = Text()
|
|
label.append(f"{prefix} ", style=f"{style} bold")
|
|
label.append(name, style=style)
|
|
if status:
|
|
label.append("\n Status: ", style="white")
|
|
label.append(status, style=f"{style} bold")
|
|
tree.label = label
|
|
|
|
def add_tree_node(self, parent: Tree, text: str, style: str = "yellow") -> Tree:
|
|
"""Add a node to the tree with consistent styling."""
|
|
return parent.add(Text(text, style=style))
|
|
|
|
def print(self, *args, **kwargs) -> None:
|
|
"""Print to console with consistent formatting if verbose is enabled."""
|
|
self.console.print(*args, **kwargs)
|
|
|
|
def print_panel(
|
|
self, content: Text, title: str, style: str = "blue", is_flow: bool = False
|
|
) -> None:
|
|
"""Print a panel with consistent formatting if verbose is enabled."""
|
|
panel = self.create_panel(content, title, style)
|
|
if is_flow:
|
|
self.print(panel)
|
|
self.print()
|
|
else:
|
|
if self.verbose:
|
|
self.print(panel)
|
|
self.print()
|
|
|
|
def update_crew_tree(
|
|
self,
|
|
tree: Optional[Tree],
|
|
crew_name: str,
|
|
source_id: str,
|
|
status: str = "completed",
|
|
) -> None:
|
|
"""Handle crew tree updates with consistent formatting."""
|
|
if not self.verbose or tree is None:
|
|
return
|
|
|
|
if status == "completed":
|
|
prefix, style = "✅ Crew:", "green"
|
|
title = "Crew Completion"
|
|
content_title = "Crew Execution Completed"
|
|
elif status == "failed":
|
|
prefix, style = "❌ Crew:", "red"
|
|
title = "Crew Failure"
|
|
content_title = "Crew Execution Failed"
|
|
else:
|
|
prefix, style = "🚀 Crew:", "cyan"
|
|
title = "Crew Execution"
|
|
content_title = "Crew Execution Started"
|
|
|
|
self.update_tree_label(
|
|
tree,
|
|
prefix,
|
|
crew_name or "Crew",
|
|
style,
|
|
)
|
|
|
|
content = self.create_status_content(
|
|
content_title,
|
|
crew_name or "Crew",
|
|
style,
|
|
ID=source_id,
|
|
)
|
|
|
|
self.print_panel(content, title, style)
|
|
|
|
def create_crew_tree(self, crew_name: str, source_id: str) -> Optional[Tree]:
|
|
"""Create and initialize a new crew tree with initial status."""
|
|
if not self.verbose:
|
|
return None
|
|
|
|
tree = Tree(
|
|
Text("🚀 Crew: ", style="cyan bold") + Text(crew_name, style="cyan")
|
|
)
|
|
|
|
content = self.create_status_content(
|
|
"Crew Execution Started",
|
|
crew_name,
|
|
"cyan",
|
|
ID=source_id,
|
|
)
|
|
|
|
self.print_panel(content, "Crew Execution Started", "cyan")
|
|
|
|
# Set the current_crew_tree attribute directly
|
|
self.current_crew_tree = tree
|
|
|
|
return tree
|
|
|
|
def create_task_branch(
|
|
self, crew_tree: Optional[Tree], task_id: str
|
|
) -> Optional[Tree]:
|
|
"""Create and initialize a task branch."""
|
|
if not self.verbose:
|
|
return None
|
|
|
|
task_content = Text()
|
|
task_content.append(f"📋 Task: {task_id}", style="yellow bold")
|
|
task_content.append("\n Status: ", style="white")
|
|
task_content.append("Executing Task...", style="yellow dim")
|
|
|
|
task_branch = None
|
|
if crew_tree:
|
|
task_branch = crew_tree.add(task_content)
|
|
self.print(crew_tree)
|
|
else:
|
|
self.print_panel(task_content, "Task Started", "yellow")
|
|
|
|
self.print()
|
|
|
|
# Set the current_task_branch attribute directly
|
|
self.current_task_branch = task_branch
|
|
|
|
return task_branch
|
|
|
|
def update_task_status(
|
|
self,
|
|
crew_tree: Optional[Tree],
|
|
task_id: str,
|
|
agent_role: str,
|
|
status: str = "completed",
|
|
) -> None:
|
|
"""Update task status in the tree."""
|
|
if not self.verbose or crew_tree is None:
|
|
return
|
|
|
|
if status == "completed":
|
|
style = "green"
|
|
status_text = "✅ Completed"
|
|
panel_title = "Task Completion"
|
|
else:
|
|
style = "red"
|
|
status_text = "❌ Failed"
|
|
panel_title = "Task Failure"
|
|
|
|
# Update tree label
|
|
for branch in crew_tree.children:
|
|
if str(task_id) in str(branch.label):
|
|
task_content = Text()
|
|
task_content.append(f"📋 Task: {task_id}", style=f"{style} bold")
|
|
task_content.append("\n Assigned to: ", style="white")
|
|
task_content.append(agent_role, style=style)
|
|
task_content.append("\n Status: ", style="white")
|
|
task_content.append(status_text, style=f"{style} bold")
|
|
branch.label = task_content
|
|
self.print(crew_tree)
|
|
break
|
|
|
|
# Show status panel
|
|
content = self.create_status_content(
|
|
f"Task {status.title()}", str(task_id), style, Agent=agent_role
|
|
)
|
|
self.print_panel(content, panel_title, style)
|
|
|
|
def create_agent_branch(
|
|
self, task_branch: Optional[Tree], agent_role: str, crew_tree: Optional[Tree]
|
|
) -> Optional[Tree]:
|
|
"""Create and initialize an agent branch."""
|
|
if not self.verbose or not task_branch or not crew_tree:
|
|
return None
|
|
|
|
agent_branch = task_branch.add("")
|
|
self.update_tree_label(
|
|
agent_branch, "🤖 Agent:", agent_role, "green", "In Progress"
|
|
)
|
|
|
|
self.print(crew_tree)
|
|
self.print()
|
|
|
|
# Set the current_agent_branch attribute directly
|
|
self.current_agent_branch = agent_branch
|
|
|
|
return agent_branch
|
|
|
|
def update_agent_status(
|
|
self,
|
|
agent_branch: Optional[Tree],
|
|
agent_role: str,
|
|
crew_tree: Optional[Tree],
|
|
status: str = "completed",
|
|
) -> None:
|
|
"""Update agent status in the tree."""
|
|
if not self.verbose or agent_branch is None or crew_tree is None:
|
|
return
|
|
|
|
self.update_tree_label(
|
|
agent_branch,
|
|
"🤖 Agent:",
|
|
agent_role,
|
|
"green",
|
|
"✅ Completed" if status == "completed" else "❌ Failed",
|
|
)
|
|
|
|
self.print(crew_tree)
|
|
self.print()
|
|
|
|
def create_flow_tree(self, flow_name: str, flow_id: str) -> Optional[Tree]:
|
|
"""Create and initialize a flow tree."""
|
|
content = self.create_status_content(
|
|
"Starting Flow Execution", flow_name, "blue", ID=flow_id
|
|
)
|
|
self.print_panel(content, "Flow Execution", "blue", is_flow=True)
|
|
|
|
# Create initial tree with flow ID
|
|
flow_label = Text()
|
|
flow_label.append("🌊 Flow: ", style="blue bold")
|
|
flow_label.append(flow_name, style="blue")
|
|
flow_label.append("\n ID: ", style="white")
|
|
flow_label.append(flow_id, style="blue")
|
|
|
|
flow_tree = Tree(flow_label)
|
|
self.add_tree_node(flow_tree, "✨ Created", "blue")
|
|
self.add_tree_node(flow_tree, "✅ Initialization Complete", "green")
|
|
|
|
return flow_tree
|
|
|
|
def start_flow(self, flow_name: str, flow_id: str) -> Optional[Tree]:
|
|
"""Initialize a flow execution tree."""
|
|
flow_tree = Tree("")
|
|
flow_label = Text()
|
|
flow_label.append("🌊 Flow: ", style="blue bold")
|
|
flow_label.append(flow_name, style="blue")
|
|
flow_label.append("\n ID: ", style="white")
|
|
flow_label.append(flow_id, style="blue")
|
|
flow_tree.label = flow_label
|
|
|
|
self.add_tree_node(flow_tree, "🧠 Starting Flow...", "yellow")
|
|
|
|
self.print(flow_tree)
|
|
self.print()
|
|
|
|
self.current_flow_tree = flow_tree
|
|
return flow_tree
|
|
|
|
def update_flow_status(
|
|
self,
|
|
flow_tree: Optional[Tree],
|
|
flow_name: str,
|
|
flow_id: str,
|
|
status: str = "completed",
|
|
) -> None:
|
|
"""Update flow status in the tree."""
|
|
if flow_tree is None:
|
|
return
|
|
|
|
# Update main flow label
|
|
self.update_tree_label(
|
|
flow_tree,
|
|
"✅ Flow Finished:" if status == "completed" else "❌ Flow Failed:",
|
|
flow_name,
|
|
"green" if status == "completed" else "red",
|
|
)
|
|
|
|
# Update initialization node status
|
|
for child in flow_tree.children:
|
|
if "Starting Flow" in str(child.label):
|
|
child.label = Text(
|
|
(
|
|
"✅ Flow Completed"
|
|
if status == "completed"
|
|
else "❌ Flow Failed"
|
|
),
|
|
style="green" if status == "completed" else "red",
|
|
)
|
|
break
|
|
|
|
content = self.create_status_content(
|
|
(
|
|
"Flow Execution Completed"
|
|
if status == "completed"
|
|
else "Flow Execution Failed"
|
|
),
|
|
flow_name,
|
|
"green" if status == "completed" else "red",
|
|
ID=flow_id,
|
|
)
|
|
self.print(flow_tree)
|
|
self.print_panel(
|
|
content, "Flow Completion", "green" if status == "completed" else "red"
|
|
)
|
|
|
|
def update_method_status(
|
|
self,
|
|
method_branch: Optional[Tree],
|
|
flow_tree: Optional[Tree],
|
|
method_name: str,
|
|
status: str = "running",
|
|
) -> Optional[Tree]:
|
|
"""Update method status in the flow tree."""
|
|
if not flow_tree:
|
|
return None
|
|
|
|
if status == "running":
|
|
prefix, style = "🔄 Running:", "yellow"
|
|
elif status == "completed":
|
|
prefix, style = "✅ Completed:", "green"
|
|
# Update initialization node when a method completes successfully
|
|
for child in flow_tree.children:
|
|
if "Starting Flow" in str(child.label):
|
|
child.label = Text("Flow Method Step", style="white")
|
|
break
|
|
else:
|
|
prefix, style = "❌ Failed:", "red"
|
|
# Update initialization node on failure
|
|
for child in flow_tree.children:
|
|
if "Starting Flow" in str(child.label):
|
|
child.label = Text("❌ Flow Step Failed", style="red")
|
|
break
|
|
|
|
if not method_branch:
|
|
# Find or create method branch
|
|
for branch in flow_tree.children:
|
|
if method_name in str(branch.label):
|
|
method_branch = branch
|
|
break
|
|
if not method_branch:
|
|
method_branch = flow_tree.add("")
|
|
|
|
method_branch.label = Text(prefix, style=f"{style} bold") + Text(
|
|
f" {method_name}", style=style
|
|
)
|
|
|
|
self.print(flow_tree)
|
|
self.print()
|
|
return method_branch
|
|
|
|
def handle_tool_usage_started(
|
|
self,
|
|
agent_branch: Optional[Tree],
|
|
tool_name: str,
|
|
crew_tree: Optional[Tree],
|
|
) -> Optional[Tree]:
|
|
"""Handle tool usage started event."""
|
|
if not self.verbose:
|
|
return None
|
|
|
|
# Use LiteAgent branch if available, otherwise use regular agent branch
|
|
branch_to_use = self.current_lite_agent_branch or agent_branch
|
|
tree_to_use = branch_to_use or crew_tree
|
|
|
|
if branch_to_use is None or tree_to_use is None:
|
|
return None
|
|
|
|
# Update tool usage count
|
|
self.tool_usage_counts[tool_name] = self.tool_usage_counts.get(tool_name, 0) + 1
|
|
|
|
# Find or create tool node
|
|
tool_branch = self.current_tool_branch
|
|
if tool_branch is None:
|
|
tool_branch = branch_to_use.add("")
|
|
self.current_tool_branch = tool_branch
|
|
|
|
# Update label with current count
|
|
self.update_tree_label(
|
|
tool_branch,
|
|
"🔧",
|
|
f"Using {tool_name} ({self.tool_usage_counts[tool_name]})",
|
|
"yellow",
|
|
)
|
|
|
|
# Only print if this is a new tool usage
|
|
if tool_branch not in branch_to_use.children:
|
|
self.print(tree_to_use)
|
|
self.print()
|
|
|
|
return tool_branch
|
|
|
|
def handle_tool_usage_finished(
|
|
self,
|
|
tool_branch: Optional[Tree],
|
|
tool_name: str,
|
|
crew_tree: Optional[Tree],
|
|
) -> None:
|
|
"""Handle tool usage finished event."""
|
|
if not self.verbose or tool_branch is None:
|
|
return
|
|
|
|
# Use LiteAgent branch if available, otherwise use crew tree
|
|
tree_to_use = self.current_lite_agent_branch or crew_tree
|
|
if tree_to_use is None:
|
|
return
|
|
|
|
# Update the existing tool node's label
|
|
self.update_tree_label(
|
|
tool_branch,
|
|
"🔧",
|
|
f"Used {tool_name} ({self.tool_usage_counts[tool_name]})",
|
|
"green",
|
|
)
|
|
|
|
# Clear the current tool branch as we're done with it
|
|
self.current_tool_branch = None
|
|
|
|
# Only print if we have a valid tree and the tool node is still in it
|
|
if isinstance(tree_to_use, Tree) and tool_branch in tree_to_use.children:
|
|
self.print(tree_to_use)
|
|
self.print()
|
|
|
|
def handle_tool_usage_error(
|
|
self,
|
|
tool_branch: Optional[Tree],
|
|
tool_name: str,
|
|
error: str,
|
|
crew_tree: Optional[Tree],
|
|
) -> None:
|
|
"""Handle tool usage error event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
# Use LiteAgent branch if available, otherwise use crew tree
|
|
tree_to_use = self.current_lite_agent_branch or crew_tree
|
|
|
|
if tool_branch:
|
|
self.update_tree_label(
|
|
tool_branch,
|
|
"🔧 Failed",
|
|
f"{tool_name} ({self.tool_usage_counts[tool_name]})",
|
|
"red",
|
|
)
|
|
if tree_to_use:
|
|
self.print(tree_to_use)
|
|
self.print()
|
|
|
|
# Show error panel
|
|
error_content = self.create_status_content(
|
|
"Tool Usage Failed", tool_name, "red", Error=error
|
|
)
|
|
self.print_panel(error_content, "Tool Error", "red")
|
|
|
|
def handle_llm_call_started(
|
|
self,
|
|
agent_branch: Optional[Tree],
|
|
crew_tree: Optional[Tree],
|
|
) -> Optional[Tree]:
|
|
"""Handle LLM call started event."""
|
|
if not self.verbose:
|
|
return None
|
|
|
|
# Use LiteAgent branch if available, otherwise use regular agent branch
|
|
branch_to_use = self.current_lite_agent_branch or agent_branch
|
|
tree_to_use = branch_to_use or crew_tree
|
|
|
|
if branch_to_use is None or tree_to_use is None:
|
|
return None
|
|
|
|
# Only add thinking status if we don't have a current tool branch
|
|
if self.current_tool_branch is None:
|
|
tool_branch = branch_to_use.add("")
|
|
self.update_tree_label(tool_branch, "🧠", "Thinking...", "blue")
|
|
self.current_tool_branch = tool_branch
|
|
self.print(tree_to_use)
|
|
self.print()
|
|
return tool_branch
|
|
return None
|
|
|
|
def handle_llm_call_completed(
|
|
self,
|
|
tool_branch: Optional[Tree],
|
|
agent_branch: Optional[Tree],
|
|
crew_tree: Optional[Tree],
|
|
) -> None:
|
|
"""Handle LLM call completed event."""
|
|
if not self.verbose or tool_branch is None:
|
|
return
|
|
|
|
# Use LiteAgent branch if available, otherwise use regular agent branch
|
|
branch_to_use = self.current_lite_agent_branch or agent_branch
|
|
tree_to_use = branch_to_use or crew_tree
|
|
|
|
if branch_to_use is None or tree_to_use is None:
|
|
return
|
|
|
|
# Remove the thinking status node when complete, but only if it exists
|
|
if "Thinking" in str(tool_branch.label):
|
|
try:
|
|
# Check if the node is actually in the children list
|
|
if tool_branch in branch_to_use.children:
|
|
branch_to_use.children.remove(tool_branch)
|
|
self.print(tree_to_use)
|
|
self.print()
|
|
except Exception:
|
|
# If any error occurs during removal, just continue without removing
|
|
pass
|
|
|
|
def handle_llm_call_failed(
|
|
self, tool_branch: Optional[Tree], error: str, crew_tree: Optional[Tree]
|
|
) -> None:
|
|
"""Handle LLM call failed event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
# Use LiteAgent branch if available, otherwise use crew tree
|
|
tree_to_use = self.current_lite_agent_branch or crew_tree
|
|
|
|
# Update tool branch if it exists
|
|
if tool_branch:
|
|
tool_branch.label = Text("❌ LLM Failed", style="red bold")
|
|
if tree_to_use:
|
|
self.print(tree_to_use)
|
|
self.print()
|
|
|
|
# Show error panel
|
|
error_content = Text()
|
|
error_content.append("❌ LLM Call Failed\n", style="red bold")
|
|
error_content.append("Error: ", style="white")
|
|
error_content.append(str(error), style="red")
|
|
|
|
self.print_panel(error_content, "LLM Error", "red")
|
|
|
|
def handle_crew_test_started(
|
|
self, crew_name: str, source_id: str, n_iterations: int
|
|
) -> Optional[Tree]:
|
|
"""Handle crew test started event."""
|
|
if not self.verbose:
|
|
return None
|
|
|
|
# Create initial panel
|
|
content = Text()
|
|
content.append("🧪 Starting Crew Test\n\n", style="blue bold")
|
|
content.append("Crew: ", style="white")
|
|
content.append(f"{crew_name}\n", style="blue")
|
|
content.append("ID: ", style="white")
|
|
content.append(str(source_id), style="blue")
|
|
content.append("\nIterations: ", style="white")
|
|
content.append(str(n_iterations), style="yellow")
|
|
|
|
self.print()
|
|
self.print_panel(content, "Test Execution", "blue")
|
|
self.print()
|
|
|
|
# Create and display the test tree
|
|
test_label = Text()
|
|
test_label.append("🧪 Test: ", style="blue bold")
|
|
test_label.append(crew_name or "Crew", style="blue")
|
|
test_label.append("\n Status: ", style="white")
|
|
test_label.append("In Progress", style="yellow")
|
|
|
|
test_tree = Tree(test_label)
|
|
self.add_tree_node(test_tree, "🔄 Running tests...", "yellow")
|
|
|
|
self.print(test_tree)
|
|
self.print()
|
|
return test_tree
|
|
|
|
def handle_crew_test_completed(
|
|
self, flow_tree: Optional[Tree], crew_name: str
|
|
) -> None:
|
|
"""Handle crew test completed event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
if flow_tree:
|
|
# Update test tree label to show completion
|
|
test_label = Text()
|
|
test_label.append("✅ Test: ", style="green bold")
|
|
test_label.append(crew_name or "Crew", style="green")
|
|
test_label.append("\n Status: ", style="white")
|
|
test_label.append("Completed", style="green bold")
|
|
flow_tree.label = test_label
|
|
|
|
# Update the running tests node
|
|
for child in flow_tree.children:
|
|
if "Running tests" in str(child.label):
|
|
child.label = Text("✅ Tests completed successfully", style="green")
|
|
break
|
|
|
|
self.print(flow_tree)
|
|
self.print()
|
|
|
|
# Create completion panel
|
|
completion_content = Text()
|
|
completion_content.append("Test Execution Completed\n", style="green bold")
|
|
completion_content.append("Crew: ", style="white")
|
|
completion_content.append(f"{crew_name}\n", style="green")
|
|
completion_content.append("Status: ", style="white")
|
|
completion_content.append("Completed", style="green")
|
|
|
|
self.print_panel(completion_content, "Test Completion", "green")
|
|
|
|
def handle_crew_train_started(self, crew_name: str, timestamp: str) -> None:
|
|
"""Handle crew train started event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
content = Text()
|
|
content.append("📋 Crew Training Started\n", style="blue bold")
|
|
content.append("Crew: ", style="white")
|
|
content.append(f"{crew_name}\n", style="blue")
|
|
content.append("Time: ", style="white")
|
|
content.append(timestamp, style="blue")
|
|
|
|
self.print_panel(content, "Training Started", "blue")
|
|
self.print()
|
|
|
|
def handle_crew_train_completed(self, crew_name: str, timestamp: str) -> None:
|
|
"""Handle crew train completed event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
content = Text()
|
|
content.append("✅ Crew Training Completed\n", style="green bold")
|
|
content.append("Crew: ", style="white")
|
|
content.append(f"{crew_name}\n", style="green")
|
|
content.append("Time: ", style="white")
|
|
content.append(timestamp, style="green")
|
|
|
|
self.print_panel(content, "Training Completed", "green")
|
|
self.print()
|
|
|
|
def handle_crew_train_failed(self, crew_name: str) -> None:
|
|
"""Handle crew train failed event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
failure_content = Text()
|
|
failure_content.append("❌ Crew Training Failed\n", style="red bold")
|
|
failure_content.append("Crew: ", style="white")
|
|
failure_content.append(crew_name or "Crew", style="red")
|
|
|
|
self.print_panel(failure_content, "Training Failure", "red")
|
|
self.print()
|
|
|
|
def handle_crew_test_failed(self, crew_name: str) -> None:
|
|
"""Handle crew test failed event."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
failure_content = Text()
|
|
failure_content.append("❌ Crew Test Failed\n", style="red bold")
|
|
failure_content.append("Crew: ", style="white")
|
|
failure_content.append(crew_name or "Crew", style="red")
|
|
|
|
self.print_panel(failure_content, "Test Failure", "red")
|
|
self.print()
|
|
|
|
def create_lite_agent_branch(self, lite_agent_role: str) -> Optional[Tree]:
|
|
"""Create and initialize a lite agent branch."""
|
|
if not self.verbose:
|
|
return None
|
|
|
|
# Create initial tree for LiteAgent if it doesn't exist
|
|
if not self.current_lite_agent_branch:
|
|
lite_agent_label = Text()
|
|
lite_agent_label.append("🤖 LiteAgent: ", style="cyan bold")
|
|
lite_agent_label.append(lite_agent_role, style="cyan")
|
|
lite_agent_label.append("\n Status: ", style="white")
|
|
lite_agent_label.append("In Progress", style="yellow")
|
|
|
|
lite_agent_tree = Tree(lite_agent_label)
|
|
self.current_lite_agent_branch = lite_agent_tree
|
|
self.print(lite_agent_tree)
|
|
self.print()
|
|
|
|
return self.current_lite_agent_branch
|
|
|
|
def update_lite_agent_status(
|
|
self,
|
|
lite_agent_branch: Optional[Tree],
|
|
lite_agent_role: str,
|
|
status: str = "completed",
|
|
**fields: Dict[str, Any],
|
|
) -> None:
|
|
"""Update lite agent status in the tree."""
|
|
if not self.verbose or lite_agent_branch is None:
|
|
return
|
|
|
|
# Determine style based on status
|
|
if status == "completed":
|
|
prefix, style = "✅ LiteAgent:", "green"
|
|
status_text = "Completed"
|
|
title = "LiteAgent Completion"
|
|
elif status == "failed":
|
|
prefix, style = "❌ LiteAgent:", "red"
|
|
status_text = "Failed"
|
|
title = "LiteAgent Error"
|
|
else:
|
|
prefix, style = "🤖 LiteAgent:", "yellow"
|
|
status_text = "In Progress"
|
|
title = "LiteAgent Status"
|
|
|
|
# Update the tree label
|
|
lite_agent_label = Text()
|
|
lite_agent_label.append(f"{prefix} ", style=f"{style} bold")
|
|
lite_agent_label.append(lite_agent_role, style=style)
|
|
lite_agent_label.append("\n Status: ", style="white")
|
|
lite_agent_label.append(status_text, style=f"{style} bold")
|
|
lite_agent_branch.label = lite_agent_label
|
|
|
|
self.print(lite_agent_branch)
|
|
self.print()
|
|
|
|
# Show status panel if additional fields are provided
|
|
if fields:
|
|
content = self.create_status_content(
|
|
f"LiteAgent {status.title()}", lite_agent_role, style, **fields
|
|
)
|
|
self.print_panel(content, title, style)
|
|
|
|
def handle_lite_agent_execution(
|
|
self,
|
|
lite_agent_role: str,
|
|
status: str = "started",
|
|
error: Any = None,
|
|
**fields: Dict[str, Any],
|
|
) -> None:
|
|
"""Handle lite agent execution events with consistent formatting."""
|
|
if not self.verbose:
|
|
return
|
|
|
|
if status == "started":
|
|
# Create or get the LiteAgent branch
|
|
lite_agent_branch = self.create_lite_agent_branch(lite_agent_role)
|
|
if lite_agent_branch and fields:
|
|
# Show initial status panel
|
|
content = self.create_status_content(
|
|
"LiteAgent Session Started", lite_agent_role, "cyan", **fields
|
|
)
|
|
self.print_panel(content, "LiteAgent Started", "cyan")
|
|
else:
|
|
# Update existing LiteAgent branch
|
|
if error:
|
|
fields["Error"] = error
|
|
self.update_lite_agent_status(
|
|
self.current_lite_agent_branch, lite_agent_role, status, **fields
|
|
)
|