Coverage for src / osiris_cli / activity_monitor.py: 0%
65 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-31 05:01 +0200
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-31 05:01 +0200
1#!/usr/bin/env python3
2"""
3Tool Activity Monitor for Osiris CLI
4Shows real-time tool usage, file operations, and agent activity
5"""
7from rich.console import Console
8from rich.panel import Panel
9from rich.table import Table
10from rich.live import Live
11from datetime import datetime
12from typing import Dict, List, Optional
13import time
15console = Console()
18class ActivityMonitor:
19 """Monitor and display agent tool activity in real-time"""
21 def __init__(self):
22 self.activities: List[Dict] = []
23 self.current_tool: Optional[str] = None
24 self.start_time: Optional[float] = None
26 def start_tool(self, tool_name: str, args: Dict):
27 """Record tool execution start"""
28 self.current_tool = tool_name
29 self.start_time = time.time()
31 activity = {
32 "tool": tool_name,
33 "args": args,
34 "start_time": datetime.now(),
35 "status": "running"
36 }
37 self.activities.append(activity)
39 # Display tool start
40 self._display_tool_start(tool_name, args)
42 def end_tool(self, result: str, success: bool = True):
43 """Record tool execution end"""
44 if not self.current_tool:
45 return
47 elapsed = time.time() - self.start_time if self.start_time else 0
49 # Update last activity
50 if self.activities:
51 self.activities[-1].update({
52 "status": "success" if success else "failed",
53 "result": result,
54 "elapsed": elapsed
55 })
57 # Display tool end
58 self._display_tool_end(self.current_tool, result, elapsed, success)
60 self.current_tool = None
61 self.start_time = None
63 def _display_tool_start(self, tool_name: str, args: Dict):
64 """Display tool execution start"""
65 # Disabled - display is handled in minimal_cli.py
66 pass
68 def _display_tool_end(self, tool_name: str, result: str, elapsed: float, success: bool):
69 """Display tool execution end"""
70 # Disabled - display is handled in minimal_cli.py
71 pass
74 def show_summary(self):
75 """Show summary of all activities"""
76 if not self.activities:
77 return
79 console.print("\n[bold]Activity Summary:[/bold]")
81 table = Table(show_header=True, box=None, padding=(0, 1))
82 table.add_column("Tool", style="cyan")
83 table.add_column("Status")
84 table.add_column("Time", style="dim")
85 table.add_column("Result", style="dim")
87 for activity in self.activities:
88 status_icon = "✓" if activity["status"] == "success" else "✗"
89 status_color = "green" if activity["status"] == "success" else "red"
90 elapsed = activity.get("elapsed", 0)
91 result = activity.get("result", "")[:50]
93 table.add_row(
94 activity["tool"],
95 f"[{status_color}]{status_icon}[/{status_color}]",
96 f"{elapsed:.2f}s",
97 result
98 )
100 console.print(table)
101 console.print()
104# Global monitor instance
105activity_monitor = ActivityMonitor()
108def monitor_tool_call(func):
109 """Decorator to monitor tool calls"""
110 def wrapper(tool_name: str, *args, **kwargs):
111 # Start monitoring
112 activity_monitor.start_tool(tool_name, kwargs)
114 try:
115 # Execute tool
116 result = func(tool_name, *args, **kwargs)
117 from .tools import normalize_tool_result
119 normalized = normalize_tool_result(tool_name, result)
120 summary = (
121 normalized.get("message")
122 or normalized.get("stdout")
123 or normalized.get("stderr")
124 or ""
125 )
126 success = normalized.get("status") == "success"
127 activity_monitor.end_tool(summary, success=success)
129 return result
130 except Exception as e:
131 # End monitoring (failure)
132 activity_monitor.end_tool(str(e), success=False)
133 raise
135 return wrapper