omnimancer-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnimancer/__init__.py +42 -0
- omnimancer/__main__.py +9 -0
- omnimancer/cli/__init__.py +8 -0
- omnimancer/cli/agent_manager.py +826 -0
- omnimancer/cli/agent_wizard.py +944 -0
- omnimancer/cli/approval_formatter.py +734 -0
- omnimancer/cli/approval_integration.py +734 -0
- omnimancer/cli/approval_prompt.py +1286 -0
- omnimancer/cli/batch_approval_display.py +617 -0
- omnimancer/cli/batch_approval_filters.py +729 -0
- omnimancer/cli/batch_operation_monitor.py +775 -0
- omnimancer/cli/commands/performance_cmd.py +624 -0
- omnimancer/cli/commands.py +757 -0
- omnimancer/cli/completion_handler.py +281 -0
- omnimancer/cli/config_setup_wizard.py +783 -0
- omnimancer/cli/dynamic_commands.py +371 -0
- omnimancer/cli/handlers/__init__.py +18 -0
- omnimancer/cli/handlers/agent_handler.py +865 -0
- omnimancer/cli/handlers/agent_persona_handler.py +1048 -0
- omnimancer/cli/handlers/custom_agent_handler.py +352 -0
- omnimancer/cli/handlers/permissions_handler.py +1609 -0
- omnimancer/cli/interface.py +6695 -0
- omnimancer/cli/performance_dashboard.py +612 -0
- omnimancer/core/__init__.py +34 -0
- omnimancer/core/agent/__init__.py +256 -0
- omnimancer/core/agent/agent_config.py +715 -0
- omnimancer/core/agent/agent_switcher.py +668 -0
- omnimancer/core/agent/approval_context.py +460 -0
- omnimancer/core/agent/approval_dialog.py +902 -0
- omnimancer/core/agent/approval_interface.py +628 -0
- omnimancer/core/agent/approval_manager.py +760 -0
- omnimancer/core/agent/cli_integration.py +470 -0
- omnimancer/core/agent/config.py +845 -0
- omnimancer/core/agent/custom_agent_integration.py +654 -0
- omnimancer/core/agent/diff_renderer.py +706 -0
- omnimancer/core/agent/file_content_display.py +503 -0
- omnimancer/core/agent/file_modification_workflow.py +658 -0
- omnimancer/core/agent/file_system_manager.py +1790 -0
- omnimancer/core/agent/input_handler.py +614 -0
- omnimancer/core/agent/metrics_collector.py +771 -0
- omnimancer/core/agent/optimization_engine.py +729 -0
- omnimancer/core/agent/performance_monitor.py +717 -0
- omnimancer/core/agent/persona.py +870 -0
- omnimancer/core/agent/persona_validator.py +672 -0
- omnimancer/core/agent/program_executor.py +748 -0
- omnimancer/core/agent/proposed_changes_integration.py +663 -0
- omnimancer/core/agent/read_before_write_errors.py +492 -0
- omnimancer/core/agent/read_before_write_ui.py +647 -0
- omnimancer/core/agent/rich_renderer.py +763 -0
- omnimancer/core/agent/status_config.py +238 -0
- omnimancer/core/agent/status_core.py +446 -0
- omnimancer/core/agent/status_integrated_engine.py +540 -0
- omnimancer/core/agent/status_manager.py +878 -0
- omnimancer/core/agent/status_ui_components.py +535 -0
- omnimancer/core/agent/template_applicator.py +548 -0
- omnimancer/core/agent/terminal_status_listener.py +394 -0
- omnimancer/core/agent/token_tracker.py +679 -0
- omnimancer/core/agent/types.py +60 -0
- omnimancer/core/agent/web_client.py +745 -0
- omnimancer/core/agent/workflow_orchestrator.py +826 -0
- omnimancer/core/agent_engine.py +1625 -0
- omnimancer/core/agent_mode_manager.py +706 -0
- omnimancer/core/agent_progress_ui.py +545 -0
- omnimancer/core/chat_manager.py +141 -0
- omnimancer/core/config_manager.py +2199 -0
- omnimancer/core/config_migration.py +772 -0
- omnimancer/core/config_provider.py +1974 -0
- omnimancer/core/config_security_validator.py +393 -0
- omnimancer/core/config_validator.py +768 -0
- omnimancer/core/conversation_manager.py +352 -0
- omnimancer/core/engine.py +787 -0
- omnimancer/core/enhanced_input.py +523 -0
- omnimancer/core/env_loader.py +83 -0
- omnimancer/core/fallback_manager.py +568 -0
- omnimancer/core/health_monitor.py +462 -0
- omnimancer/core/history_manager.py +462 -0
- omnimancer/core/mcp_integration_layer.py +878 -0
- omnimancer/core/models.py +1889 -0
- omnimancer/core/provider_capabilities.py +403 -0
- omnimancer/core/provider_initializer.py +450 -0
- omnimancer/core/provider_registry.py +432 -0
- omnimancer/core/security/__init__.py +16 -0
- omnimancer/core/security/approval_workflow.py +406 -0
- omnimancer/core/security/audit_logger.py +511 -0
- omnimancer/core/security/permission_controller.py +511 -0
- omnimancer/core/security/sandbox_manager.py +379 -0
- omnimancer/core/security/security_manager.py +530 -0
- omnimancer/core/setup_wizard.py +345 -0
- omnimancer/core/setup_wizard_core.py +449 -0
- omnimancer/core/setup_wizard_guide_generator.py +376 -0
- omnimancer/core/setup_wizard_provider_setup.py +454 -0
- omnimancer/core/setup_wizard_ui.py +317 -0
- omnimancer/core/setup_wizard_validation.py +371 -0
- omnimancer/core/signal_handler.py +174 -0
- omnimancer/mcp/__init__.py +11 -0
- omnimancer/mcp/client.py +725 -0
- omnimancer/mcp/manager.py +649 -0
- omnimancer/providers/__init__.py +24 -0
- omnimancer/providers/azure.py +608 -0
- omnimancer/providers/base.py +262 -0
- omnimancer/providers/bedrock.py +711 -0
- omnimancer/providers/claude.py +426 -0
- omnimancer/providers/claude_code.py +406 -0
- omnimancer/providers/cohere.py +412 -0
- omnimancer/providers/factory.py +988 -0
- omnimancer/providers/gemini.py +708 -0
- omnimancer/providers/mistral.py +554 -0
- omnimancer/providers/ollama.py +510 -0
- omnimancer/providers/openai.py +362 -0
- omnimancer/providers/openrouter.py +709 -0
- omnimancer/providers/perplexity.py +476 -0
- omnimancer/providers/vertex.py +617 -0
- omnimancer/providers/xai.py +484 -0
- omnimancer/ui/__init__.py +6 -0
- omnimancer/ui/cancellation_handler.py +235 -0
- omnimancer/ui/progress_indicator.py +318 -0
- omnimancer/utils/__init__.py +22 -0
- omnimancer/utils/error_handler.py +589 -0
- omnimancer/utils/errors.py +667 -0
- omnimancer/utils/retry.py +238 -0
- omnimancer_cli-0.1.0.dist-info/METADATA +413 -0
- omnimancer_cli-0.1.0.dist-info/RECORD +126 -0
- omnimancer_cli-0.1.0.dist-info/WHEEL +5 -0
- omnimancer_cli-0.1.0.dist-info/entry_points.txt +4 -0
- omnimancer_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- omnimancer_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Performance monitoring CLI command for Omnimancer.
|
|
3
|
+
|
|
4
|
+
Provides command-line access to performance metrics, dashboards, and optimization suggestions.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import sys
|
|
9
|
+
from datetime import datetime, timedelta
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.table import Table
|
|
16
|
+
|
|
17
|
+
from ...core.agent.metrics_collector import (
|
|
18
|
+
get_metrics_collector,
|
|
19
|
+
initialize_metrics_collection,
|
|
20
|
+
)
|
|
21
|
+
from ...core.agent.optimization_engine import (
|
|
22
|
+
AlertLevel,
|
|
23
|
+
OptimizationCategory,
|
|
24
|
+
get_optimization_engine,
|
|
25
|
+
initialize_optimization_engine,
|
|
26
|
+
)
|
|
27
|
+
from ...core.agent.performance_monitor import (
|
|
28
|
+
get_performance_monitor,
|
|
29
|
+
initialize_performance_monitoring,
|
|
30
|
+
)
|
|
31
|
+
from ...core.agent.token_tracker import get_token_tracker
|
|
32
|
+
from ..performance_dashboard import (
|
|
33
|
+
create_performance_dashboard,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@click.group()
|
|
38
|
+
@click.option("--debug", is_flag=True, help="Enable debug output")
|
|
39
|
+
@click.pass_context
|
|
40
|
+
def performance(ctx, debug):
|
|
41
|
+
"""Performance monitoring and optimization commands."""
|
|
42
|
+
ctx.ensure_object(dict)
|
|
43
|
+
ctx.obj["debug"] = debug
|
|
44
|
+
|
|
45
|
+
if debug:
|
|
46
|
+
import logging
|
|
47
|
+
|
|
48
|
+
logging.getLogger("omnimancer.core.agent").setLevel(logging.DEBUG)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@performance.command()
|
|
52
|
+
@click.option(
|
|
53
|
+
"--start-monitoring",
|
|
54
|
+
is_flag=True,
|
|
55
|
+
help="Start performance monitoring services",
|
|
56
|
+
)
|
|
57
|
+
@click.option(
|
|
58
|
+
"--format",
|
|
59
|
+
"output_format",
|
|
60
|
+
type=click.Choice(["table", "json"]),
|
|
61
|
+
default="table",
|
|
62
|
+
help="Output format",
|
|
63
|
+
)
|
|
64
|
+
@click.pass_context
|
|
65
|
+
def status(ctx, start_monitoring, output_format):
|
|
66
|
+
"""Show performance monitoring status."""
|
|
67
|
+
console = Console()
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
if start_monitoring:
|
|
71
|
+
console.print("[yellow]Initializing performance monitoring...[/yellow]")
|
|
72
|
+
|
|
73
|
+
# Initialize all components
|
|
74
|
+
performance_monitor = initialize_performance_monitoring(auto_start=True)
|
|
75
|
+
metrics_collector = initialize_metrics_collection(auto_start=True)
|
|
76
|
+
optimization_engine = initialize_optimization_engine(auto_start=True)
|
|
77
|
+
|
|
78
|
+
console.print("[green]✓ Performance monitoring started[/green]")
|
|
79
|
+
else:
|
|
80
|
+
performance_monitor = get_performance_monitor()
|
|
81
|
+
metrics_collector = get_metrics_collector()
|
|
82
|
+
optimization_engine = get_optimization_engine()
|
|
83
|
+
|
|
84
|
+
# Gather status information
|
|
85
|
+
status_info = {
|
|
86
|
+
"monitoring_active": (
|
|
87
|
+
performance_monitor.is_monitoring
|
|
88
|
+
if hasattr(performance_monitor, "is_monitoring")
|
|
89
|
+
else False
|
|
90
|
+
),
|
|
91
|
+
"metrics_collecting": (
|
|
92
|
+
metrics_collector.is_collecting
|
|
93
|
+
if hasattr(metrics_collector, "is_collecting")
|
|
94
|
+
else False
|
|
95
|
+
),
|
|
96
|
+
"optimization_running": (
|
|
97
|
+
optimization_engine.is_running
|
|
98
|
+
if hasattr(optimization_engine, "is_running")
|
|
99
|
+
else False
|
|
100
|
+
),
|
|
101
|
+
"timestamp": datetime.now().isoformat(),
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Get recent statistics
|
|
105
|
+
dashboard_data = performance_monitor.get_performance_dashboard_data()
|
|
106
|
+
status_info.update(
|
|
107
|
+
{
|
|
108
|
+
"active_alerts": len(dashboard_data.get("active_alerts", [])),
|
|
109
|
+
"suggestions_count": len(dashboard_data.get("suggestions", [])),
|
|
110
|
+
"recent_snapshot": dashboard_data.get("current_snapshot", {}),
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Display results
|
|
115
|
+
if output_format == "json":
|
|
116
|
+
console.print(json.dumps(status_info, indent=2, default=str))
|
|
117
|
+
else:
|
|
118
|
+
_display_status_table(console, status_info)
|
|
119
|
+
|
|
120
|
+
except Exception as e:
|
|
121
|
+
console.print(f"[red]Error checking performance status: {e}[/red]")
|
|
122
|
+
if ctx.obj.get("debug"):
|
|
123
|
+
console.print_exception()
|
|
124
|
+
sys.exit(1)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@performance.command()
|
|
128
|
+
@click.option(
|
|
129
|
+
"--view",
|
|
130
|
+
type=click.Choice(
|
|
131
|
+
[
|
|
132
|
+
"overview",
|
|
133
|
+
"tokens",
|
|
134
|
+
"performance",
|
|
135
|
+
"resources",
|
|
136
|
+
"alerts",
|
|
137
|
+
"suggestions",
|
|
138
|
+
]
|
|
139
|
+
),
|
|
140
|
+
default="overview",
|
|
141
|
+
help="Dashboard view to display",
|
|
142
|
+
)
|
|
143
|
+
@click.option("--live", is_flag=True, help="Start live updating dashboard")
|
|
144
|
+
@click.option("--export", type=click.Path(), help="Export performance report to file")
|
|
145
|
+
@click.pass_context
|
|
146
|
+
def dashboard(ctx, view, live, export):
|
|
147
|
+
"""Show performance dashboard."""
|
|
148
|
+
console = Console()
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
dashboard = create_performance_dashboard()
|
|
152
|
+
|
|
153
|
+
if export:
|
|
154
|
+
export_path = Path(export)
|
|
155
|
+
console.print(f"[yellow]Exporting performance report...[/yellow]")
|
|
156
|
+
result_path = dashboard.export_report(export_path)
|
|
157
|
+
console.print(f"[green]Report exported to {result_path}[/green]")
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
if live:
|
|
161
|
+
console.print(f"[yellow]Starting live dashboard ({view} view)...[/yellow]")
|
|
162
|
+
dashboard.start_live_dashboard(view)
|
|
163
|
+
else:
|
|
164
|
+
if view == "overview":
|
|
165
|
+
dashboard.show_overview()
|
|
166
|
+
else:
|
|
167
|
+
dashboard.show_detailed_view(view)
|
|
168
|
+
|
|
169
|
+
except KeyboardInterrupt:
|
|
170
|
+
console.print("\n[yellow]Dashboard stopped.[/yellow]")
|
|
171
|
+
except Exception as e:
|
|
172
|
+
console.print(f"[red]Error displaying dashboard: {e}[/red]")
|
|
173
|
+
if ctx.obj.get("debug"):
|
|
174
|
+
console.print_exception()
|
|
175
|
+
sys.exit(1)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@performance.command()
|
|
179
|
+
@click.option("--hours", type=int, default=1, help="Time window in hours")
|
|
180
|
+
@click.option("--provider", help="Filter by specific provider")
|
|
181
|
+
@click.option(
|
|
182
|
+
"--format",
|
|
183
|
+
"output_format",
|
|
184
|
+
type=click.Choice(["table", "json"]),
|
|
185
|
+
default="table",
|
|
186
|
+
help="Output format",
|
|
187
|
+
)
|
|
188
|
+
@click.pass_context
|
|
189
|
+
def tokens(ctx, hours, provider, output_format):
|
|
190
|
+
"""Show token usage statistics."""
|
|
191
|
+
console = Console()
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
token_tracker = get_token_tracker()
|
|
195
|
+
|
|
196
|
+
# Get usage summary
|
|
197
|
+
time_window = timedelta(hours=hours)
|
|
198
|
+
summary = token_tracker.get_usage_summary(time_window)
|
|
199
|
+
|
|
200
|
+
if output_format == "json":
|
|
201
|
+
console.print(json.dumps(summary, indent=2, default=str))
|
|
202
|
+
else:
|
|
203
|
+
_display_token_usage_table(console, summary, hours)
|
|
204
|
+
|
|
205
|
+
except Exception as e:
|
|
206
|
+
console.print(f"[red]Error retrieving token usage: {e}[/red]")
|
|
207
|
+
if ctx.obj.get("debug"):
|
|
208
|
+
console.print_exception()
|
|
209
|
+
sys.exit(1)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@performance.command()
|
|
213
|
+
@click.option(
|
|
214
|
+
"--category",
|
|
215
|
+
type=click.Choice(
|
|
216
|
+
[
|
|
217
|
+
"cost_reduction",
|
|
218
|
+
"performance_improvement",
|
|
219
|
+
"resource_efficiency",
|
|
220
|
+
"reliability_enhancement",
|
|
221
|
+
"user_experience",
|
|
222
|
+
]
|
|
223
|
+
),
|
|
224
|
+
help="Filter by optimization category",
|
|
225
|
+
)
|
|
226
|
+
@click.option(
|
|
227
|
+
"--format",
|
|
228
|
+
"output_format",
|
|
229
|
+
type=click.Choice(["table", "json"]),
|
|
230
|
+
default="table",
|
|
231
|
+
help="Output format",
|
|
232
|
+
)
|
|
233
|
+
@click.pass_context
|
|
234
|
+
def suggestions(ctx, category, output_format):
|
|
235
|
+
"""Show optimization suggestions."""
|
|
236
|
+
console = Console()
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
optimization_engine = get_optimization_engine()
|
|
240
|
+
|
|
241
|
+
# Get current suggestions
|
|
242
|
+
if category:
|
|
243
|
+
category_enum = OptimizationCategory(category)
|
|
244
|
+
current_suggestions = optimization_engine.get_current_suggestions(
|
|
245
|
+
category_enum
|
|
246
|
+
)
|
|
247
|
+
else:
|
|
248
|
+
current_suggestions = optimization_engine.get_current_suggestions()
|
|
249
|
+
|
|
250
|
+
# Also get token tracker suggestions
|
|
251
|
+
token_tracker = get_token_tracker()
|
|
252
|
+
token_suggestions = token_tracker.get_cost_optimization_suggestions()
|
|
253
|
+
|
|
254
|
+
if output_format == "json":
|
|
255
|
+
data = {
|
|
256
|
+
"optimization_suggestions": [s.__dict__ for s in current_suggestions],
|
|
257
|
+
"token_suggestions": token_suggestions,
|
|
258
|
+
}
|
|
259
|
+
console.print(json.dumps(data, indent=2, default=str))
|
|
260
|
+
else:
|
|
261
|
+
_display_suggestions_table(console, current_suggestions, token_suggestions)
|
|
262
|
+
|
|
263
|
+
except Exception as e:
|
|
264
|
+
console.print(f"[red]Error retrieving suggestions: {e}[/red]")
|
|
265
|
+
if ctx.obj.get("debug"):
|
|
266
|
+
console.print_exception()
|
|
267
|
+
sys.exit(1)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@performance.command()
|
|
271
|
+
@click.option(
|
|
272
|
+
"--level",
|
|
273
|
+
type=click.Choice(["info", "warning", "critical", "emergency"]),
|
|
274
|
+
help="Filter by alert level",
|
|
275
|
+
)
|
|
276
|
+
@click.option(
|
|
277
|
+
"--format",
|
|
278
|
+
"output_format",
|
|
279
|
+
type=click.Choice(["table", "json"]),
|
|
280
|
+
default="table",
|
|
281
|
+
help="Output format",
|
|
282
|
+
)
|
|
283
|
+
@click.pass_context
|
|
284
|
+
def alerts(ctx, level, output_format):
|
|
285
|
+
"""Show performance alerts."""
|
|
286
|
+
console = Console()
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
optimization_engine = get_optimization_engine()
|
|
290
|
+
|
|
291
|
+
# Get active alerts
|
|
292
|
+
if level:
|
|
293
|
+
level_enum = AlertLevel(level)
|
|
294
|
+
active_alerts = optimization_engine.get_active_alerts(level_enum)
|
|
295
|
+
else:
|
|
296
|
+
active_alerts = optimization_engine.get_active_alerts()
|
|
297
|
+
|
|
298
|
+
if output_format == "json":
|
|
299
|
+
data = [alert.__dict__ for alert in active_alerts]
|
|
300
|
+
console.print(json.dumps(data, indent=2, default=str))
|
|
301
|
+
else:
|
|
302
|
+
_display_alerts_table(console, active_alerts)
|
|
303
|
+
|
|
304
|
+
except Exception as e:
|
|
305
|
+
console.print(f"[red]Error retrieving alerts: {e}[/red]")
|
|
306
|
+
if ctx.obj.get("debug"):
|
|
307
|
+
console.print_exception()
|
|
308
|
+
sys.exit(1)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@performance.command()
|
|
312
|
+
@click.option("--metric", help="Specific metric to analyze")
|
|
313
|
+
@click.option("--days", type=int, default=7, help="Analysis period in days")
|
|
314
|
+
@click.option(
|
|
315
|
+
"--format",
|
|
316
|
+
"output_format",
|
|
317
|
+
type=click.Choice(["table", "json"]),
|
|
318
|
+
default="table",
|
|
319
|
+
help="Output format",
|
|
320
|
+
)
|
|
321
|
+
@click.pass_context
|
|
322
|
+
def analyze(ctx, metric, days, output_format):
|
|
323
|
+
"""Analyze performance patterns and trends."""
|
|
324
|
+
console = Console()
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
token_tracker = get_token_tracker()
|
|
328
|
+
metrics_collector = get_metrics_collector()
|
|
329
|
+
|
|
330
|
+
# Analyze usage patterns
|
|
331
|
+
usage_patterns = token_tracker.analyze_usage_patterns(days)
|
|
332
|
+
|
|
333
|
+
analysis_results = {
|
|
334
|
+
"usage_patterns": usage_patterns.__dict__,
|
|
335
|
+
"analysis_period_days": days,
|
|
336
|
+
"timestamp": datetime.now().isoformat(),
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
# Add metric-specific analysis if requested
|
|
340
|
+
if metric:
|
|
341
|
+
# Get anomalies for specific metric
|
|
342
|
+
anomalies = metrics_collector.detect_anomalies(metric)
|
|
343
|
+
analysis_results["anomalies"] = anomalies
|
|
344
|
+
|
|
345
|
+
if output_format == "json":
|
|
346
|
+
console.print(json.dumps(analysis_results, indent=2, default=str))
|
|
347
|
+
else:
|
|
348
|
+
_display_analysis_results(console, analysis_results)
|
|
349
|
+
|
|
350
|
+
except Exception as e:
|
|
351
|
+
console.print(f"[red]Error performing analysis: {e}[/red]")
|
|
352
|
+
if ctx.obj.get("debug"):
|
|
353
|
+
console.print_exception()
|
|
354
|
+
sys.exit(1)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
@performance.command()
|
|
358
|
+
@click.option("--output", "-o", type=click.Path(), help="Output file path")
|
|
359
|
+
@click.option(
|
|
360
|
+
"--format",
|
|
361
|
+
"output_format",
|
|
362
|
+
type=click.Choice(["json", "csv"]),
|
|
363
|
+
default="json",
|
|
364
|
+
help="Export format",
|
|
365
|
+
)
|
|
366
|
+
@click.option("--days", type=int, default=7, help="Data period to export (days)")
|
|
367
|
+
@click.pass_context
|
|
368
|
+
def export(ctx, output, output_format, days):
|
|
369
|
+
"""Export performance metrics to file."""
|
|
370
|
+
console = Console()
|
|
371
|
+
|
|
372
|
+
try:
|
|
373
|
+
if not output:
|
|
374
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
375
|
+
output = f"omnimancer_performance_{timestamp}.{output_format}"
|
|
376
|
+
|
|
377
|
+
output_path = Path(output)
|
|
378
|
+
time_window = timedelta(days=days)
|
|
379
|
+
|
|
380
|
+
console.print(f"[yellow]Exporting {days} days of performance data...[/yellow]")
|
|
381
|
+
|
|
382
|
+
# Export metrics
|
|
383
|
+
metrics_collector = get_metrics_collector()
|
|
384
|
+
metrics_path = metrics_collector.export_metrics(
|
|
385
|
+
time_window, f"metrics_{output_path.stem}.json"
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# Export token usage
|
|
389
|
+
token_tracker = get_token_tracker()
|
|
390
|
+
token_tracker.save_usage_history(f"tokens_{output_path.stem}.json")
|
|
391
|
+
|
|
392
|
+
# Create combined report
|
|
393
|
+
dashboard = create_performance_dashboard()
|
|
394
|
+
report_path = dashboard.export_report(output_path)
|
|
395
|
+
|
|
396
|
+
console.print(f"[green]✓ Performance data exported to {report_path}[/green]")
|
|
397
|
+
console.print(f"[green]✓ Metrics data exported to {metrics_path}[/green]")
|
|
398
|
+
|
|
399
|
+
except Exception as e:
|
|
400
|
+
console.print(f"[red]Error exporting data: {e}[/red]")
|
|
401
|
+
if ctx.obj.get("debug"):
|
|
402
|
+
console.print_exception()
|
|
403
|
+
sys.exit(1)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
# Helper functions for display
|
|
407
|
+
def _display_status_table(console: Console, status_info: Dict[str, Any]) -> None:
|
|
408
|
+
"""Display status information in table format."""
|
|
409
|
+
table = Table(title="Performance Monitoring Status")
|
|
410
|
+
table.add_column("Component", style="cyan")
|
|
411
|
+
table.add_column("Status", justify="center")
|
|
412
|
+
table.add_column("Details")
|
|
413
|
+
|
|
414
|
+
# Monitoring status
|
|
415
|
+
monitoring_status = (
|
|
416
|
+
"🟢 Active" if status_info.get("monitoring_active") else "🔴 Inactive"
|
|
417
|
+
)
|
|
418
|
+
table.add_row("Performance Monitor", monitoring_status, "Real-time monitoring")
|
|
419
|
+
|
|
420
|
+
# Metrics collection
|
|
421
|
+
metrics_status = (
|
|
422
|
+
"🟢 Active" if status_info.get("metrics_collecting") else "🔴 Inactive"
|
|
423
|
+
)
|
|
424
|
+
table.add_row("Metrics Collection", metrics_status, "System metrics gathering")
|
|
425
|
+
|
|
426
|
+
# Optimization engine
|
|
427
|
+
optimization_status = (
|
|
428
|
+
"🟢 Running" if status_info.get("optimization_running") else "🔴 Stopped"
|
|
429
|
+
)
|
|
430
|
+
table.add_row(
|
|
431
|
+
"Optimization Engine",
|
|
432
|
+
optimization_status,
|
|
433
|
+
"Alert and suggestion generation",
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Statistics
|
|
437
|
+
alerts_count = status_info.get("active_alerts", 0)
|
|
438
|
+
suggestions_count = status_info.get("suggestions_count", 0)
|
|
439
|
+
|
|
440
|
+
table.add_row("Active Alerts", f"{alerts_count}", "Performance warnings")
|
|
441
|
+
table.add_row("Suggestions", f"{suggestions_count}", "Optimization recommendations")
|
|
442
|
+
|
|
443
|
+
console.print(table)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def _display_token_usage_table(
|
|
447
|
+
console: Console, summary: Dict[str, Any], hours: int
|
|
448
|
+
) -> None:
|
|
449
|
+
"""Display token usage in table format."""
|
|
450
|
+
table = Table(title=f"Token Usage (Last {hours} hours)")
|
|
451
|
+
table.add_column("Metric", style="cyan")
|
|
452
|
+
table.add_column("Value", justify="right")
|
|
453
|
+
table.add_column("Rate", justify="right")
|
|
454
|
+
|
|
455
|
+
total_tokens = summary.get("total_tokens", 0)
|
|
456
|
+
total_requests = summary.get("total_requests", 0)
|
|
457
|
+
total_cost = summary.get("total_cost", 0.0)
|
|
458
|
+
|
|
459
|
+
table.add_row(
|
|
460
|
+
"Total Tokens",
|
|
461
|
+
f"{total_tokens:,}",
|
|
462
|
+
f"{total_tokens/(hours*60):.0f}/min",
|
|
463
|
+
)
|
|
464
|
+
table.add_row(
|
|
465
|
+
"Total Requests",
|
|
466
|
+
f"{total_requests:,}",
|
|
467
|
+
f"{total_requests/(hours*60):.1f}/min",
|
|
468
|
+
)
|
|
469
|
+
table.add_row(
|
|
470
|
+
"Total Cost", f"${total_cost:.4f}", f"${total_cost/(hours*60):.5f}/min"
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
if total_requests > 0:
|
|
474
|
+
table.add_row("Avg Tokens/Request", f"{total_tokens/total_requests:.0f}", "-")
|
|
475
|
+
table.add_row("Avg Cost/Request", f"${total_cost/total_requests:.5f}", "-")
|
|
476
|
+
|
|
477
|
+
console.print(table)
|
|
478
|
+
|
|
479
|
+
# Provider breakdown
|
|
480
|
+
provider_breakdown = summary.get("provider_breakdown", {})
|
|
481
|
+
if provider_breakdown:
|
|
482
|
+
provider_table = Table(title="Provider Breakdown")
|
|
483
|
+
provider_table.add_column("Provider", style="cyan")
|
|
484
|
+
provider_table.add_column("Tokens", justify="right")
|
|
485
|
+
provider_table.add_column("Requests", justify="right")
|
|
486
|
+
provider_table.add_column("Cost", justify="right")
|
|
487
|
+
|
|
488
|
+
for provider, stats in provider_breakdown.items():
|
|
489
|
+
provider_table.add_row(
|
|
490
|
+
provider,
|
|
491
|
+
f"{stats['tokens']:,}",
|
|
492
|
+
f"{stats['requests']:,}",
|
|
493
|
+
f"${stats['cost']:.4f}",
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
console.print()
|
|
497
|
+
console.print(provider_table)
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def _display_suggestions_table(
|
|
501
|
+
console: Console,
|
|
502
|
+
optimization_suggestions: List[Any],
|
|
503
|
+
token_suggestions: List[Dict[str, Any]],
|
|
504
|
+
) -> None:
|
|
505
|
+
"""Display optimization suggestions in table format."""
|
|
506
|
+
if not optimization_suggestions and not token_suggestions:
|
|
507
|
+
console.print("[green]No optimization suggestions at this time[/green]")
|
|
508
|
+
return
|
|
509
|
+
|
|
510
|
+
table = Table(title="Optimization Suggestions")
|
|
511
|
+
table.add_column("Type", style="cyan")
|
|
512
|
+
table.add_column("Title")
|
|
513
|
+
table.add_column("Impact")
|
|
514
|
+
table.add_column("Difficulty")
|
|
515
|
+
|
|
516
|
+
# Add optimization suggestions
|
|
517
|
+
for suggestion in optimization_suggestions:
|
|
518
|
+
table.add_row(
|
|
519
|
+
(
|
|
520
|
+
suggestion.optimization_type.value
|
|
521
|
+
if hasattr(suggestion, "optimization_type")
|
|
522
|
+
else "General"
|
|
523
|
+
),
|
|
524
|
+
suggestion.title if hasattr(suggestion, "title") else "N/A",
|
|
525
|
+
(
|
|
526
|
+
suggestion.potential_improvement
|
|
527
|
+
if hasattr(suggestion, "potential_improvement")
|
|
528
|
+
else "Unknown"
|
|
529
|
+
),
|
|
530
|
+
(
|
|
531
|
+
suggestion.implementation_difficulty
|
|
532
|
+
if hasattr(suggestion, "implementation_difficulty")
|
|
533
|
+
else "Unknown"
|
|
534
|
+
),
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
# Add token suggestions
|
|
538
|
+
for suggestion in token_suggestions:
|
|
539
|
+
table.add_row(
|
|
540
|
+
suggestion.get("type", "token"),
|
|
541
|
+
suggestion.get("title", "Token Optimization"),
|
|
542
|
+
suggestion.get("potential_savings", "Unknown"),
|
|
543
|
+
"Easy",
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
console.print(table)
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def _display_alerts_table(console: Console, alerts: List[Any]) -> None:
|
|
550
|
+
"""Display performance alerts in table format."""
|
|
551
|
+
if not alerts:
|
|
552
|
+
console.print("[green]No active alerts[/green]")
|
|
553
|
+
return
|
|
554
|
+
|
|
555
|
+
table = Table(title="Performance Alerts")
|
|
556
|
+
table.add_column("Level", style="cyan")
|
|
557
|
+
table.add_column("Title")
|
|
558
|
+
table.add_column("Description")
|
|
559
|
+
table.add_column("Time")
|
|
560
|
+
|
|
561
|
+
for alert in alerts:
|
|
562
|
+
level_color = {
|
|
563
|
+
"info": "blue",
|
|
564
|
+
"warning": "yellow",
|
|
565
|
+
"critical": "red",
|
|
566
|
+
"emergency": "bright_red",
|
|
567
|
+
}.get(alert.level.value if hasattr(alert, "level") else "info", "white")
|
|
568
|
+
|
|
569
|
+
table.add_row(
|
|
570
|
+
f"[{level_color}]{alert.level.value if hasattr(alert, 'level') else 'Unknown'}[/{level_color}]",
|
|
571
|
+
alert.title if hasattr(alert, "title") else "Unknown Alert",
|
|
572
|
+
(alert.description if hasattr(alert, "description") else "No description"),
|
|
573
|
+
(
|
|
574
|
+
alert.timestamp.strftime("%H:%M:%S")
|
|
575
|
+
if hasattr(alert, "timestamp")
|
|
576
|
+
else "Unknown"
|
|
577
|
+
),
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
console.print(table)
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def _display_analysis_results(console: Console, results: Dict[str, Any]) -> None:
|
|
584
|
+
"""Display analysis results in readable format."""
|
|
585
|
+
usage_patterns = results.get("usage_patterns", {})
|
|
586
|
+
|
|
587
|
+
# Summary table
|
|
588
|
+
table = Table(
|
|
589
|
+
title=f"Performance Analysis ({results.get('analysis_period_days', 7)} days)"
|
|
590
|
+
)
|
|
591
|
+
table.add_column("Metric", style="cyan")
|
|
592
|
+
table.add_column("Value")
|
|
593
|
+
|
|
594
|
+
table.add_row("Total Tokens", f"{usage_patterns.get('total_tokens', 0):,}")
|
|
595
|
+
table.add_row("Total Requests", f"{usage_patterns.get('total_requests', 0):,}")
|
|
596
|
+
table.add_row("Total Cost", f"${usage_patterns.get('total_cost', 0.0):.4f}")
|
|
597
|
+
table.add_row(
|
|
598
|
+
"Avg Tokens/Request",
|
|
599
|
+
f"{usage_patterns.get('average_tokens_per_request', 0):.0f}",
|
|
600
|
+
)
|
|
601
|
+
table.add_row(
|
|
602
|
+
"Peak Usage Time",
|
|
603
|
+
str(usage_patterns.get("peak_usage_time", "Unknown")),
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
console.print(table)
|
|
607
|
+
|
|
608
|
+
# Efficiency metrics
|
|
609
|
+
if usage_patterns.get("average_context_utilization", 0) > 0:
|
|
610
|
+
efficiency_table = Table(title="Efficiency Metrics")
|
|
611
|
+
efficiency_table.add_column("Metric", style="cyan")
|
|
612
|
+
efficiency_table.add_column("Score")
|
|
613
|
+
|
|
614
|
+
efficiency_table.add_row(
|
|
615
|
+
"Context Utilization",
|
|
616
|
+
f"{usage_patterns.get('average_context_utilization', 0)*100:.1f}%",
|
|
617
|
+
)
|
|
618
|
+
efficiency_table.add_row(
|
|
619
|
+
"Response Efficiency",
|
|
620
|
+
f"{usage_patterns.get('average_response_efficiency', 0)*100:.1f}%",
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
console.print()
|
|
624
|
+
console.print(efficiency_table)
|