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,540 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Status-Integrated Agent Engine for Omnimancer.
|
|
3
|
+
|
|
4
|
+
This module provides an enhanced AgentEngine that integrates with the status
|
|
5
|
+
tracking and display system, providing real-time updates on agent operations
|
|
6
|
+
and state changes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import uuid
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Dict, Optional
|
|
14
|
+
|
|
15
|
+
from ..agent_engine import AgentEngine
|
|
16
|
+
from ..config_manager import ConfigManager
|
|
17
|
+
from .status_core import (
|
|
18
|
+
AgentOperation,
|
|
19
|
+
AgentStatus,
|
|
20
|
+
)
|
|
21
|
+
from .status_core import OperationType as StatusOperationType
|
|
22
|
+
from .status_manager import UnifiedStatusManager as AgentStatusManager
|
|
23
|
+
from .status_manager import (
|
|
24
|
+
get_status_manager,
|
|
25
|
+
)
|
|
26
|
+
from .types import Operation, OperationResult, OperationType
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class StatusIntegratedAgentEngine(AgentEngine):
|
|
32
|
+
"""
|
|
33
|
+
Agent engine enhanced with comprehensive status tracking and display.
|
|
34
|
+
|
|
35
|
+
This class extends the base AgentEngine to provide real-time status updates,
|
|
36
|
+
operation tracking, and integration with the status display system.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
config_manager: ConfigManager,
|
|
42
|
+
base_path: Optional[Path] = None,
|
|
43
|
+
status_manager: Optional[AgentStatusManager] = None,
|
|
44
|
+
enable_status_display: bool = True,
|
|
45
|
+
):
|
|
46
|
+
"""
|
|
47
|
+
Initialize the status-integrated agent engine.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
config_manager: Configuration manager instance
|
|
51
|
+
base_path: Base path for file system operations
|
|
52
|
+
status_manager: Optional status manager (uses global if not provided)
|
|
53
|
+
enable_status_display: Whether to enable status display
|
|
54
|
+
"""
|
|
55
|
+
super().__init__(config_manager, base_path)
|
|
56
|
+
|
|
57
|
+
# Status system integration
|
|
58
|
+
self.status_manager = status_manager or get_status_manager()
|
|
59
|
+
self.enable_status_display = enable_status_display
|
|
60
|
+
|
|
61
|
+
# Operation mapping for status tracking
|
|
62
|
+
self.operation_mapping = {
|
|
63
|
+
OperationType.FILE_READ: StatusOperationType.FILE_READ,
|
|
64
|
+
OperationType.FILE_WRITE: StatusOperationType.FILE_WRITE,
|
|
65
|
+
OperationType.FILE_DELETE: StatusOperationType.FILE_DELETE,
|
|
66
|
+
OperationType.DIRECTORY_CREATE: StatusOperationType.DIRECTORY_CREATE,
|
|
67
|
+
OperationType.DIRECTORY_DELETE: StatusOperationType.DIRECTORY_DELETE,
|
|
68
|
+
OperationType.COMMAND_EXECUTION: StatusOperationType.COMMAND_EXECUTION,
|
|
69
|
+
OperationType.WEB_REQUEST: StatusOperationType.WEB_REQUEST,
|
|
70
|
+
OperationType.API_CALL: StatusOperationType.API_CALL,
|
|
71
|
+
OperationType.APPROVAL_REQUEST: StatusOperationType.APPROVAL_REQUEST,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Active operation tracking
|
|
75
|
+
self.active_status_operations: Dict[str, str] = (
|
|
76
|
+
{}
|
|
77
|
+
) # agent_operation_id -> status_operation_id
|
|
78
|
+
|
|
79
|
+
# Agent identification
|
|
80
|
+
self.agent_id = "main_agent" # Could be made configurable
|
|
81
|
+
|
|
82
|
+
logger.info(
|
|
83
|
+
"StatusIntegratedAgentEngine initialized with status tracking enabled"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
async def initialize_status_system(self) -> None:
|
|
87
|
+
"""Initialize the integrated status system."""
|
|
88
|
+
try:
|
|
89
|
+
# Initialize status manager
|
|
90
|
+
await self.status_manager.initialize()
|
|
91
|
+
|
|
92
|
+
# Set initial agent status
|
|
93
|
+
await self.status_manager.set_agent_status(
|
|
94
|
+
self.agent_id,
|
|
95
|
+
AgentStatus.ENABLED,
|
|
96
|
+
{
|
|
97
|
+
"initialization_time": datetime.now(),
|
|
98
|
+
"engine_type": "StatusIntegratedAgentEngine",
|
|
99
|
+
"base_path": (
|
|
100
|
+
str(self.file_system.base_path)
|
|
101
|
+
if hasattr(self, "file_system")
|
|
102
|
+
else None
|
|
103
|
+
),
|
|
104
|
+
},
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
logger.info(f"Status system initialized for agent {self.agent_id}")
|
|
108
|
+
|
|
109
|
+
except Exception as e:
|
|
110
|
+
logger.error(f"Failed to initialize status system: {e}")
|
|
111
|
+
# Don't fail the entire engine if status system fails
|
|
112
|
+
self.enable_status_display = False
|
|
113
|
+
|
|
114
|
+
async def shutdown_status_system(self) -> None:
|
|
115
|
+
"""Shutdown the integrated status system."""
|
|
116
|
+
try:
|
|
117
|
+
# Set agent status to shutting down
|
|
118
|
+
await self.status_manager.set_agent_status(
|
|
119
|
+
self.agent_id,
|
|
120
|
+
AgentStatus.SHUTTING_DOWN,
|
|
121
|
+
{"shutdown_time": datetime.now()},
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Cancel any active operations
|
|
125
|
+
for agent_op_id, status_op_id in list(
|
|
126
|
+
self.active_status_operations.items()
|
|
127
|
+
):
|
|
128
|
+
await self.status_manager.cancel_operation(
|
|
129
|
+
status_op_id, "Engine shutdown"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Shutdown status manager
|
|
133
|
+
await self.status_manager.shutdown()
|
|
134
|
+
|
|
135
|
+
logger.info("Status system shutdown complete")
|
|
136
|
+
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"Error during status system shutdown: {e}")
|
|
139
|
+
|
|
140
|
+
async def execute_with_approval(self, operation: Operation) -> OperationResult:
|
|
141
|
+
"""
|
|
142
|
+
Execute operation with approval workflow and status tracking.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
operation: Operation to execute
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Result of the operation
|
|
149
|
+
"""
|
|
150
|
+
status_operation = None
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
# Create status operation for tracking
|
|
154
|
+
if self.enable_status_display:
|
|
155
|
+
status_operation = await self._create_status_operation(operation)
|
|
156
|
+
|
|
157
|
+
# Set agent to running state
|
|
158
|
+
if self.enable_status_display:
|
|
159
|
+
await self.status_manager.set_agent_status(
|
|
160
|
+
self.agent_id,
|
|
161
|
+
AgentStatus.RUNNING,
|
|
162
|
+
{
|
|
163
|
+
"current_operation": (
|
|
164
|
+
operation.type.value
|
|
165
|
+
if hasattr(operation.type, "value")
|
|
166
|
+
else str(operation.type)
|
|
167
|
+
)
|
|
168
|
+
},
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Execute the operation using parent class method
|
|
172
|
+
result = await super().execute_with_approval(operation)
|
|
173
|
+
|
|
174
|
+
# Update status based on result
|
|
175
|
+
if self.enable_status_display and status_operation:
|
|
176
|
+
if result.success:
|
|
177
|
+
await self.status_manager.complete_operation(
|
|
178
|
+
status_operation.operation_id,
|
|
179
|
+
{
|
|
180
|
+
"result_data": result.data,
|
|
181
|
+
"execution_details": result.details,
|
|
182
|
+
},
|
|
183
|
+
)
|
|
184
|
+
else:
|
|
185
|
+
await self.status_manager.fail_operation(
|
|
186
|
+
status_operation.operation_id,
|
|
187
|
+
result.error or "Operation failed without specific error",
|
|
188
|
+
{
|
|
189
|
+
"error_details": result.details,
|
|
190
|
+
"failure_context": result.error,
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Set agent back to enabled state
|
|
195
|
+
if self.enable_status_display:
|
|
196
|
+
await self.status_manager.set_agent_status(
|
|
197
|
+
self.agent_id,
|
|
198
|
+
AgentStatus.ENABLED,
|
|
199
|
+
{
|
|
200
|
+
"last_operation_result": (
|
|
201
|
+
"success" if result.success else "failed"
|
|
202
|
+
)
|
|
203
|
+
},
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
# Handle operation failure in status system
|
|
210
|
+
if self.enable_status_display and status_operation:
|
|
211
|
+
await self.status_manager.fail_operation(
|
|
212
|
+
status_operation.operation_id,
|
|
213
|
+
f"Exception during execution: {e}",
|
|
214
|
+
{
|
|
215
|
+
"exception_type": type(e).__name__,
|
|
216
|
+
"exception_details": str(e),
|
|
217
|
+
},
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Set agent to error state
|
|
221
|
+
if self.enable_status_display:
|
|
222
|
+
await self.status_manager.set_agent_status(
|
|
223
|
+
self.agent_id,
|
|
224
|
+
AgentStatus.ERROR,
|
|
225
|
+
{"error_message": str(e), "error_time": datetime.now()},
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# Re-raise the exception
|
|
229
|
+
raise
|
|
230
|
+
finally:
|
|
231
|
+
# Clean up operation tracking
|
|
232
|
+
if status_operation and operation.id in self.active_status_operations:
|
|
233
|
+
del self.active_status_operations[operation.id]
|
|
234
|
+
|
|
235
|
+
async def _create_status_operation(self, operation: Operation) -> AgentOperation:
|
|
236
|
+
"""
|
|
237
|
+
Create a status operation for tracking.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
operation: The agent operation to track
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
Created status operation
|
|
244
|
+
"""
|
|
245
|
+
# Map operation type
|
|
246
|
+
status_op_type = self.operation_mapping.get(
|
|
247
|
+
operation.type, StatusOperationType.API_CALL
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
# Create operation description
|
|
251
|
+
description = self._generate_operation_description(operation)
|
|
252
|
+
|
|
253
|
+
# Create status operation
|
|
254
|
+
status_operation = AgentOperation(
|
|
255
|
+
operation_id=str(uuid.uuid4()),
|
|
256
|
+
operation_type=status_op_type,
|
|
257
|
+
description=description,
|
|
258
|
+
agent_id=self.agent_id,
|
|
259
|
+
metadata={
|
|
260
|
+
"original_operation_id": operation.id,
|
|
261
|
+
"original_operation_type": (
|
|
262
|
+
operation.type.value
|
|
263
|
+
if hasattr(operation.type, "value")
|
|
264
|
+
else str(operation.type)
|
|
265
|
+
),
|
|
266
|
+
"operation_data": operation.data,
|
|
267
|
+
"requires_approval": operation.requires_approval,
|
|
268
|
+
},
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# Start tracking
|
|
272
|
+
await self.status_manager.start_operation(status_operation)
|
|
273
|
+
|
|
274
|
+
# Keep reference for updates
|
|
275
|
+
self.active_status_operations[operation.id] = status_operation.operation_id
|
|
276
|
+
|
|
277
|
+
return status_operation
|
|
278
|
+
|
|
279
|
+
def _generate_operation_description(self, operation: Operation) -> str:
|
|
280
|
+
"""
|
|
281
|
+
Generate a user-friendly description for an operation.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
operation: The operation to describe
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Human-readable description
|
|
288
|
+
"""
|
|
289
|
+
op_type = operation.type
|
|
290
|
+
data = operation.data
|
|
291
|
+
|
|
292
|
+
try:
|
|
293
|
+
if hasattr(op_type, "value"):
|
|
294
|
+
type_str = op_type.value
|
|
295
|
+
else:
|
|
296
|
+
type_str = str(op_type)
|
|
297
|
+
|
|
298
|
+
if type_str == "FILE_READ" and "path" in data:
|
|
299
|
+
return f"Reading file: {Path(data['path']).name}"
|
|
300
|
+
elif type_str == "FILE_WRITE" and "path" in data:
|
|
301
|
+
return f"Writing to file: {Path(data['path']).name}"
|
|
302
|
+
elif type_str == "FILE_DELETE" and "path" in data:
|
|
303
|
+
return f"Deleting file: {Path(data['path']).name}"
|
|
304
|
+
elif type_str == "DIRECTORY_CREATE" and "path" in data:
|
|
305
|
+
return f"Creating directory: {Path(data['path']).name}"
|
|
306
|
+
elif type_str == "DIRECTORY_DELETE" and "path" in data:
|
|
307
|
+
return f"Deleting directory: {Path(data['path']).name}"
|
|
308
|
+
elif type_str == "COMMAND_EXECUTION" and "command" in data:
|
|
309
|
+
cmd = data["command"]
|
|
310
|
+
return f"Executing: {cmd[:30]}{'...' if len(cmd) > 30 else ''}"
|
|
311
|
+
elif type_str == "WEB_REQUEST" and "url" in data:
|
|
312
|
+
return f"Web request to: {data['url']}"
|
|
313
|
+
elif type_str == "API_CALL":
|
|
314
|
+
return "Making API call"
|
|
315
|
+
elif type_str == "APPROVAL_REQUEST":
|
|
316
|
+
return "Requesting user approval"
|
|
317
|
+
else:
|
|
318
|
+
return f"Executing {type_str.lower().replace('_', ' ')}"
|
|
319
|
+
|
|
320
|
+
except Exception as e:
|
|
321
|
+
logger.warning(f"Failed to generate operation description: {e}")
|
|
322
|
+
return f"Executing {type_str.lower().replace('_', ' ') if type_str else 'operation'}"
|
|
323
|
+
|
|
324
|
+
async def update_operation_progress(
|
|
325
|
+
self,
|
|
326
|
+
operation_id: str,
|
|
327
|
+
progress: float,
|
|
328
|
+
description: Optional[str] = None,
|
|
329
|
+
) -> None:
|
|
330
|
+
"""
|
|
331
|
+
Update progress of an operation.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
operation_id: ID of the agent operation
|
|
335
|
+
progress: Progress percentage (0-100)
|
|
336
|
+
description: Optional progress description
|
|
337
|
+
"""
|
|
338
|
+
if (
|
|
339
|
+
not self.enable_status_display
|
|
340
|
+
or operation_id not in self.active_status_operations
|
|
341
|
+
):
|
|
342
|
+
return
|
|
343
|
+
|
|
344
|
+
status_operation_id = self.active_status_operations[operation_id]
|
|
345
|
+
|
|
346
|
+
try:
|
|
347
|
+
await self.status_manager.update_operation_progress(
|
|
348
|
+
status_operation_id, progress, description
|
|
349
|
+
)
|
|
350
|
+
except Exception as e:
|
|
351
|
+
logger.error(f"Failed to update operation progress: {e}")
|
|
352
|
+
|
|
353
|
+
async def get_status_summary(self) -> Dict[str, Any]:
|
|
354
|
+
"""
|
|
355
|
+
Get a summary of current agent status.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
Dictionary with status information
|
|
359
|
+
"""
|
|
360
|
+
if not self.enable_status_display:
|
|
361
|
+
return {"status_display": "disabled"}
|
|
362
|
+
|
|
363
|
+
try:
|
|
364
|
+
agent_status = self.status_manager.get_agent_status(self.agent_id)
|
|
365
|
+
agent_metadata = self.status_manager.get_agent_metadata(self.agent_id)
|
|
366
|
+
active_operations = self.status_manager.get_active_operations(self.agent_id)
|
|
367
|
+
system_stats = self.status_manager.get_stats()
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
"agent_id": self.agent_id,
|
|
371
|
+
"status": agent_status.value if agent_status else "unknown",
|
|
372
|
+
"metadata": agent_metadata,
|
|
373
|
+
"active_operations_count": len(active_operations),
|
|
374
|
+
"active_operations": [
|
|
375
|
+
{
|
|
376
|
+
"id": op.operation_id,
|
|
377
|
+
"type": op.operation_type.value,
|
|
378
|
+
"description": op.description,
|
|
379
|
+
"progress": op.progress_percentage,
|
|
380
|
+
"duration": (op.duration.total_seconds() if op.duration else 0),
|
|
381
|
+
}
|
|
382
|
+
for op in active_operations
|
|
383
|
+
],
|
|
384
|
+
"system_stats": system_stats,
|
|
385
|
+
"status_stream_running": self.status_manager.running,
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
except Exception as e:
|
|
389
|
+
logger.error(f"Failed to get status summary: {e}")
|
|
390
|
+
return {"error": f"Failed to get status: {e}"}
|
|
391
|
+
|
|
392
|
+
def is_status_display_enabled(self) -> bool:
|
|
393
|
+
"""Check if status display is enabled."""
|
|
394
|
+
return self.enable_status_display
|
|
395
|
+
|
|
396
|
+
def enable_status_display_mode(self) -> None:
|
|
397
|
+
"""Enable status display mode."""
|
|
398
|
+
self.enable_status_display = True
|
|
399
|
+
|
|
400
|
+
def disable_status_display_mode(self) -> None:
|
|
401
|
+
"""Disable status display mode."""
|
|
402
|
+
self.enable_status_display = False
|
|
403
|
+
|
|
404
|
+
async def start_status_monitoring(self) -> bool:
|
|
405
|
+
"""
|
|
406
|
+
Start status monitoring and display.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
True if monitoring started successfully
|
|
410
|
+
"""
|
|
411
|
+
try:
|
|
412
|
+
if not self.enable_status_display:
|
|
413
|
+
return False
|
|
414
|
+
|
|
415
|
+
# Initialize if not already done
|
|
416
|
+
if not self.status_manager._event_processor_task:
|
|
417
|
+
await self.status_manager.initialize()
|
|
418
|
+
|
|
419
|
+
# Status manager handles stream initialization
|
|
420
|
+
|
|
421
|
+
logger.info("Status monitoring started successfully")
|
|
422
|
+
return True
|
|
423
|
+
|
|
424
|
+
except Exception as e:
|
|
425
|
+
logger.error(f"Failed to start status monitoring: {e}")
|
|
426
|
+
return False
|
|
427
|
+
|
|
428
|
+
async def stop_status_monitoring(self) -> bool:
|
|
429
|
+
"""
|
|
430
|
+
Stop status monitoring and display.
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
True if monitoring stopped successfully
|
|
434
|
+
"""
|
|
435
|
+
try:
|
|
436
|
+
# The unified status manager handles stream shutdown
|
|
437
|
+
|
|
438
|
+
# Update agent status
|
|
439
|
+
await self.status_manager.set_agent_status(
|
|
440
|
+
self.agent_id,
|
|
441
|
+
AgentStatus.DISABLED,
|
|
442
|
+
{"monitoring_stopped": datetime.now()},
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
logger.info("Status monitoring stopped successfully")
|
|
446
|
+
return True
|
|
447
|
+
|
|
448
|
+
except Exception as e:
|
|
449
|
+
logger.error(f"Failed to stop status monitoring: {e}")
|
|
450
|
+
return False
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
# Factory function to create a fully integrated engine
|
|
454
|
+
async def create_status_integrated_engine(
|
|
455
|
+
config_manager: ConfigManager,
|
|
456
|
+
base_path: Optional[Path] = None,
|
|
457
|
+
auto_initialize: bool = True,
|
|
458
|
+
) -> StatusIntegratedAgentEngine:
|
|
459
|
+
"""
|
|
460
|
+
Create a status-integrated agent engine with automatic setup.
|
|
461
|
+
|
|
462
|
+
Args:
|
|
463
|
+
config_manager: Configuration manager instance
|
|
464
|
+
base_path: Base path for file system operations
|
|
465
|
+
auto_initialize: Whether to automatically initialize the status system
|
|
466
|
+
|
|
467
|
+
Returns:
|
|
468
|
+
Fully configured status-integrated engine
|
|
469
|
+
"""
|
|
470
|
+
# Create engine
|
|
471
|
+
engine = StatusIntegratedAgentEngine(config_manager, base_path)
|
|
472
|
+
|
|
473
|
+
# Auto-initialize if requested
|
|
474
|
+
if auto_initialize:
|
|
475
|
+
try:
|
|
476
|
+
await engine.initialize_status_system()
|
|
477
|
+
await engine.start_status_monitoring()
|
|
478
|
+
logger.info("Status-integrated engine created and initialized")
|
|
479
|
+
except Exception as e:
|
|
480
|
+
logger.error(f"Failed to auto-initialize status system: {e}")
|
|
481
|
+
# Continue with engine creation but status display disabled
|
|
482
|
+
engine.disable_status_display_mode()
|
|
483
|
+
|
|
484
|
+
return engine
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
# Context manager for temporary status tracking
|
|
488
|
+
class StatusTrackingContext:
|
|
489
|
+
"""Context manager for temporary status tracking within operations."""
|
|
490
|
+
|
|
491
|
+
def __init__(self, engine: StatusIntegratedAgentEngine, operation_name: str):
|
|
492
|
+
self.engine = engine
|
|
493
|
+
self.operation_name = operation_name
|
|
494
|
+
self.operation_id = None
|
|
495
|
+
|
|
496
|
+
async def __aenter__(self):
|
|
497
|
+
if self.engine.enable_status_display:
|
|
498
|
+
# Create a temporary operation
|
|
499
|
+
from .types import Operation as TempOperation
|
|
500
|
+
from .types import OperationType as TempOperationType
|
|
501
|
+
|
|
502
|
+
temp_operation = TempOperation(
|
|
503
|
+
id=str(uuid.uuid4()),
|
|
504
|
+
type=TempOperationType.API_CALL, # Generic type
|
|
505
|
+
data={"description": self.operation_name},
|
|
506
|
+
requires_approval=False,
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
await self.engine._create_status_operation(temp_operation)
|
|
510
|
+
self.operation_id = temp_operation.id
|
|
511
|
+
|
|
512
|
+
return self
|
|
513
|
+
|
|
514
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
515
|
+
if self.engine.enable_status_display and self.operation_id:
|
|
516
|
+
status_operation_id = self.engine.active_status_operations.get(
|
|
517
|
+
self.operation_id
|
|
518
|
+
)
|
|
519
|
+
if status_operation_id:
|
|
520
|
+
if exc_type:
|
|
521
|
+
await self.engine.status_manager.fail_operation(
|
|
522
|
+
status_operation_id,
|
|
523
|
+
f"Context operation failed: {exc_val}",
|
|
524
|
+
{"exception_type": exc_type.__name__},
|
|
525
|
+
)
|
|
526
|
+
else:
|
|
527
|
+
await self.engine.status_manager.complete_operation(
|
|
528
|
+
status_operation_id, {"context_result": "success"}
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
# Clean up
|
|
532
|
+
if self.operation_id in self.engine.active_status_operations:
|
|
533
|
+
del self.engine.active_status_operations[self.operation_id]
|
|
534
|
+
|
|
535
|
+
async def update_progress(self, progress: float, description: Optional[str] = None):
|
|
536
|
+
"""Update progress of the tracked operation."""
|
|
537
|
+
if self.operation_id:
|
|
538
|
+
await self.engine.update_operation_progress(
|
|
539
|
+
self.operation_id, progress, description
|
|
540
|
+
)
|