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,826 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Workflow Orchestrator for continuous multi-step AI operations.
|
|
3
|
+
|
|
4
|
+
This module provides the capability for the AI agent to execute multiple
|
|
5
|
+
operations in sequence automatically, similar to how Claude Code works.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
15
|
+
|
|
16
|
+
from rich.console import Console
|
|
17
|
+
from rich.markdown import Markdown
|
|
18
|
+
from rich.panel import Panel
|
|
19
|
+
|
|
20
|
+
from ...cli.batch_approval_display import BatchApprovalPanel
|
|
21
|
+
|
|
22
|
+
# Import existing UI components
|
|
23
|
+
from ...ui.progress_indicator import OperationType as ProgressOperationType
|
|
24
|
+
from ...ui.progress_indicator import (
|
|
25
|
+
ProgressIndicator,
|
|
26
|
+
)
|
|
27
|
+
from ..agent.approval_manager import EnhancedApprovalManager
|
|
28
|
+
from ..agent.file_system_manager import FileSystemManager
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class WorkflowStepType(Enum):
|
|
34
|
+
"""Types of workflow steps."""
|
|
35
|
+
|
|
36
|
+
ANALYZE = "analyze"
|
|
37
|
+
LIST_FILES = "list_files"
|
|
38
|
+
READ_FILE = "read_file"
|
|
39
|
+
WRITE_FILE = "write_file"
|
|
40
|
+
EXECUTE_COMMAND = "execute_command"
|
|
41
|
+
CHECK_CONFIG = "check_config"
|
|
42
|
+
DETECT_TECH_STACK = "detect_tech_stack"
|
|
43
|
+
CREATE_STRUCTURE = "create_structure"
|
|
44
|
+
INSTALL_DEPENDENCIES = "install_dependencies"
|
|
45
|
+
RUN_TESTS = "run_tests"
|
|
46
|
+
VALIDATE = "validate"
|
|
47
|
+
CUSTOM = "custom"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class WorkflowStatus(Enum):
|
|
51
|
+
"""Status of workflow execution."""
|
|
52
|
+
|
|
53
|
+
PENDING = "pending"
|
|
54
|
+
RUNNING = "running"
|
|
55
|
+
PAUSED = "paused"
|
|
56
|
+
COMPLETED = "completed"
|
|
57
|
+
FAILED = "failed"
|
|
58
|
+
CANCELLED = "cancelled"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class WorkflowStep:
|
|
63
|
+
"""Represents a single step in a workflow."""
|
|
64
|
+
|
|
65
|
+
name: str
|
|
66
|
+
type: WorkflowStepType
|
|
67
|
+
description: str
|
|
68
|
+
action: Optional[Callable] = None
|
|
69
|
+
parameters: Dict[str, Any] = field(default_factory=dict)
|
|
70
|
+
requires_approval: bool = False
|
|
71
|
+
continue_on_error: bool = False
|
|
72
|
+
dependencies: List[str] = field(default_factory=list)
|
|
73
|
+
result: Optional[Any] = None
|
|
74
|
+
status: WorkflowStatus = WorkflowStatus.PENDING
|
|
75
|
+
started_at: Optional[datetime] = None
|
|
76
|
+
completed_at: Optional[datetime] = None
|
|
77
|
+
error: Optional[str] = None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class WorkflowContext:
|
|
82
|
+
"""Context shared across workflow steps."""
|
|
83
|
+
|
|
84
|
+
working_directory: Path
|
|
85
|
+
data: Dict[str, Any] = field(default_factory=dict)
|
|
86
|
+
console: Console = field(default_factory=Console)
|
|
87
|
+
history: List[WorkflowStep] = field(default_factory=list)
|
|
88
|
+
|
|
89
|
+
def set(self, key: str, value: Any) -> None:
|
|
90
|
+
"""Set a value in the context."""
|
|
91
|
+
self.data[key] = value
|
|
92
|
+
|
|
93
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
94
|
+
"""Get a value from the context."""
|
|
95
|
+
return self.data.get(key, default)
|
|
96
|
+
|
|
97
|
+
def update(self, **kwargs) -> None:
|
|
98
|
+
"""Update multiple values in the context."""
|
|
99
|
+
self.data.update(kwargs)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class WorkflowOrchestrator:
|
|
103
|
+
"""
|
|
104
|
+
Orchestrates multi-step workflows for autonomous AI operations.
|
|
105
|
+
|
|
106
|
+
This enables the AI to execute a series of operations automatically,
|
|
107
|
+
continuing through each step without stopping, similar to Claude Code.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
file_system: Optional[FileSystemManager] = None,
|
|
113
|
+
approval_manager: Optional[EnhancedApprovalManager] = None,
|
|
114
|
+
executor: Optional[Any] = None,
|
|
115
|
+
console: Optional[Console] = None,
|
|
116
|
+
engine: Optional[Any] = None,
|
|
117
|
+
):
|
|
118
|
+
"""Initialize the workflow orchestrator."""
|
|
119
|
+
self.file_system = file_system
|
|
120
|
+
self.approval_manager = approval_manager
|
|
121
|
+
self.executor = executor
|
|
122
|
+
self.console = console or Console()
|
|
123
|
+
self.engine = engine # Reference to the main engine for AI calls
|
|
124
|
+
self.workflows: Dict[str, List[WorkflowStep]] = {}
|
|
125
|
+
self.current_workflow: Optional[str] = None
|
|
126
|
+
self.context: Optional[WorkflowContext] = None
|
|
127
|
+
|
|
128
|
+
# Initialize UI components for clean display
|
|
129
|
+
self.progress_indicator = ProgressIndicator(self.console)
|
|
130
|
+
self.approval_panel = BatchApprovalPanel(self.console)
|
|
131
|
+
|
|
132
|
+
# Register built-in workflows
|
|
133
|
+
self._register_builtin_workflows()
|
|
134
|
+
|
|
135
|
+
def _register_builtin_workflows(self) -> None:
|
|
136
|
+
"""Register built-in workflow templates."""
|
|
137
|
+
|
|
138
|
+
# General Action Workflow - handles any user request
|
|
139
|
+
self.register_workflow(
|
|
140
|
+
"general_action",
|
|
141
|
+
[
|
|
142
|
+
WorkflowStep(
|
|
143
|
+
name="understand_request",
|
|
144
|
+
type=WorkflowStepType.ANALYZE,
|
|
145
|
+
description="Understanding user request and requirements",
|
|
146
|
+
action=self._understand_request_action,
|
|
147
|
+
parameters={},
|
|
148
|
+
),
|
|
149
|
+
WorkflowStep(
|
|
150
|
+
name="plan_approach",
|
|
151
|
+
type=WorkflowStepType.ANALYZE,
|
|
152
|
+
description="Planning approach and identifying needed actions",
|
|
153
|
+
action=self._plan_approach_action,
|
|
154
|
+
dependencies=["understand_request"],
|
|
155
|
+
),
|
|
156
|
+
WorkflowStep(
|
|
157
|
+
name="execute_action",
|
|
158
|
+
type=WorkflowStepType.CUSTOM,
|
|
159
|
+
description="Executing the planned actions",
|
|
160
|
+
action=self._execute_action,
|
|
161
|
+
dependencies=["plan_approach"],
|
|
162
|
+
),
|
|
163
|
+
WorkflowStep(
|
|
164
|
+
name="verify_results",
|
|
165
|
+
type=WorkflowStepType.VALIDATE,
|
|
166
|
+
description="Verifying action completion and results",
|
|
167
|
+
action=self._verify_results_action,
|
|
168
|
+
dependencies=["execute_action"],
|
|
169
|
+
),
|
|
170
|
+
WorkflowStep(
|
|
171
|
+
name="provide_summary",
|
|
172
|
+
type=WorkflowStepType.CUSTOM,
|
|
173
|
+
description="Providing summary of completed work",
|
|
174
|
+
action=self._provide_summary_action,
|
|
175
|
+
dependencies=["verify_results"],
|
|
176
|
+
),
|
|
177
|
+
],
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Project Analysis Workflow
|
|
181
|
+
self.register_workflow(
|
|
182
|
+
"project_analysis",
|
|
183
|
+
[
|
|
184
|
+
WorkflowStep(
|
|
185
|
+
name="list_directory",
|
|
186
|
+
type=WorkflowStepType.LIST_FILES,
|
|
187
|
+
description="List files and directories in the project",
|
|
188
|
+
action=self._list_directory_action,
|
|
189
|
+
parameters={"path": "."},
|
|
190
|
+
),
|
|
191
|
+
WorkflowStep(
|
|
192
|
+
name="detect_tech_stack",
|
|
193
|
+
type=WorkflowStepType.DETECT_TECH_STACK,
|
|
194
|
+
description="Detect technology stack from project files",
|
|
195
|
+
action=self._detect_tech_stack_action,
|
|
196
|
+
dependencies=["list_directory"],
|
|
197
|
+
),
|
|
198
|
+
WorkflowStep(
|
|
199
|
+
name="check_configuration",
|
|
200
|
+
type=WorkflowStepType.CHECK_CONFIG,
|
|
201
|
+
description="Check for configuration files",
|
|
202
|
+
action=self._check_configuration_action,
|
|
203
|
+
dependencies=["list_directory"],
|
|
204
|
+
),
|
|
205
|
+
WorkflowStep(
|
|
206
|
+
name="analyze_structure",
|
|
207
|
+
type=WorkflowStepType.ANALYZE,
|
|
208
|
+
description="Analyze project structure and patterns",
|
|
209
|
+
action=self._analyze_structure_action,
|
|
210
|
+
dependencies=["list_directory", "detect_tech_stack"],
|
|
211
|
+
),
|
|
212
|
+
WorkflowStep(
|
|
213
|
+
name="generate_summary",
|
|
214
|
+
type=WorkflowStepType.CUSTOM,
|
|
215
|
+
description="Generate project analysis summary",
|
|
216
|
+
action=self._generate_summary_action,
|
|
217
|
+
dependencies=[
|
|
218
|
+
"detect_tech_stack",
|
|
219
|
+
"check_configuration",
|
|
220
|
+
"analyze_structure",
|
|
221
|
+
],
|
|
222
|
+
),
|
|
223
|
+
],
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# File Modification Workflow
|
|
227
|
+
self.register_workflow(
|
|
228
|
+
"file_modification",
|
|
229
|
+
[
|
|
230
|
+
WorkflowStep(
|
|
231
|
+
name="read_original",
|
|
232
|
+
type=WorkflowStepType.READ_FILE,
|
|
233
|
+
description="Read the original file content",
|
|
234
|
+
action=self._read_file_action,
|
|
235
|
+
),
|
|
236
|
+
WorkflowStep(
|
|
237
|
+
name="prepare_changes",
|
|
238
|
+
type=WorkflowStepType.CUSTOM,
|
|
239
|
+
description="Prepare file modifications",
|
|
240
|
+
action=self._prepare_changes_action,
|
|
241
|
+
dependencies=["read_original"],
|
|
242
|
+
),
|
|
243
|
+
WorkflowStep(
|
|
244
|
+
name="show_diff",
|
|
245
|
+
type=WorkflowStepType.CUSTOM,
|
|
246
|
+
description="Display changes for review",
|
|
247
|
+
action=self._show_diff_action,
|
|
248
|
+
dependencies=["prepare_changes"],
|
|
249
|
+
requires_approval=True,
|
|
250
|
+
),
|
|
251
|
+
WorkflowStep(
|
|
252
|
+
name="apply_changes",
|
|
253
|
+
type=WorkflowStepType.WRITE_FILE,
|
|
254
|
+
description="Apply approved changes to file",
|
|
255
|
+
action=self._write_file_action,
|
|
256
|
+
dependencies=["show_diff"],
|
|
257
|
+
),
|
|
258
|
+
WorkflowStep(
|
|
259
|
+
name="validate_changes",
|
|
260
|
+
type=WorkflowStepType.VALIDATE,
|
|
261
|
+
description="Validate the applied changes",
|
|
262
|
+
action=self._validate_changes_action,
|
|
263
|
+
dependencies=["apply_changes"],
|
|
264
|
+
),
|
|
265
|
+
],
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
def register_workflow(self, name: str, steps: List[WorkflowStep]) -> None:
|
|
269
|
+
"""Register a workflow template."""
|
|
270
|
+
self.workflows[name] = steps
|
|
271
|
+
|
|
272
|
+
async def execute_workflow(
|
|
273
|
+
self,
|
|
274
|
+
workflow_name: str,
|
|
275
|
+
context: Optional[WorkflowContext] = None,
|
|
276
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
277
|
+
) -> WorkflowContext:
|
|
278
|
+
"""
|
|
279
|
+
Execute a complete workflow automatically.
|
|
280
|
+
|
|
281
|
+
This is the main entry point that enables continuous execution
|
|
282
|
+
of multiple steps without stopping.
|
|
283
|
+
"""
|
|
284
|
+
if workflow_name not in self.workflows:
|
|
285
|
+
raise ValueError(f"Unknown workflow: {workflow_name}")
|
|
286
|
+
|
|
287
|
+
# Initialize context
|
|
288
|
+
self.context = context or WorkflowContext(
|
|
289
|
+
working_directory=Path.cwd(), console=self.console
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
# Pass engine reference to context
|
|
293
|
+
self.context.engine = self.engine
|
|
294
|
+
|
|
295
|
+
if parameters:
|
|
296
|
+
self.context.update(**parameters)
|
|
297
|
+
|
|
298
|
+
self.current_workflow = workflow_name
|
|
299
|
+
steps = self.workflows[workflow_name].copy()
|
|
300
|
+
|
|
301
|
+
# Display workflow plan
|
|
302
|
+
await self._display_workflow_plan(workflow_name, steps)
|
|
303
|
+
|
|
304
|
+
# Execute workflow steps with progress tracking
|
|
305
|
+
for i, step in enumerate(steps, 1):
|
|
306
|
+
# Check dependencies
|
|
307
|
+
if not self._check_dependencies(step, self.context.history):
|
|
308
|
+
step.status = WorkflowStatus.FAILED
|
|
309
|
+
step.error = "Dependencies not met"
|
|
310
|
+
self.context.history.append(step)
|
|
311
|
+
|
|
312
|
+
if not step.continue_on_error:
|
|
313
|
+
break
|
|
314
|
+
continue
|
|
315
|
+
|
|
316
|
+
# Start progress tracking for this step
|
|
317
|
+
operation_id = f"step_{i}"
|
|
318
|
+
progress_type = self._get_progress_operation_type(step.type)
|
|
319
|
+
self.progress_indicator.start_operation(
|
|
320
|
+
operation_id, progress_type, f"{step.name}: {step.description}"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
try:
|
|
324
|
+
step.status = WorkflowStatus.RUNNING
|
|
325
|
+
step.started_at = datetime.now()
|
|
326
|
+
|
|
327
|
+
# Request approval if needed
|
|
328
|
+
if step.requires_approval and self.approval_manager:
|
|
329
|
+
if not await self._request_approval(step):
|
|
330
|
+
step.status = WorkflowStatus.CANCELLED
|
|
331
|
+
self.context.history.append(step)
|
|
332
|
+
self.progress_indicator.complete_operation(
|
|
333
|
+
operation_id, "cancelled"
|
|
334
|
+
)
|
|
335
|
+
break
|
|
336
|
+
|
|
337
|
+
# Execute the step action
|
|
338
|
+
if step.action:
|
|
339
|
+
# Merge step parameters with context parameters
|
|
340
|
+
merged_params = {**step.parameters, **self.context.data}
|
|
341
|
+
step.result = await step.action(self.context, merged_params)
|
|
342
|
+
|
|
343
|
+
step.status = WorkflowStatus.COMPLETED
|
|
344
|
+
step.completed_at = datetime.now()
|
|
345
|
+
|
|
346
|
+
# Complete progress tracking
|
|
347
|
+
self.progress_indicator.complete_operation(operation_id, "completed")
|
|
348
|
+
|
|
349
|
+
except Exception as e:
|
|
350
|
+
step.status = WorkflowStatus.FAILED
|
|
351
|
+
step.error = str(e)
|
|
352
|
+
step.completed_at = datetime.now()
|
|
353
|
+
|
|
354
|
+
logger.error(f"Step {step.name} failed: {e}")
|
|
355
|
+
self.progress_indicator.complete_operation(operation_id, "failed")
|
|
356
|
+
|
|
357
|
+
if not step.continue_on_error:
|
|
358
|
+
break
|
|
359
|
+
|
|
360
|
+
finally:
|
|
361
|
+
self.context.history.append(step)
|
|
362
|
+
|
|
363
|
+
# Display workflow summary
|
|
364
|
+
await self._display_workflow_summary()
|
|
365
|
+
|
|
366
|
+
return self.context
|
|
367
|
+
|
|
368
|
+
async def _display_workflow_plan(
|
|
369
|
+
self, name: str, steps: List[WorkflowStep]
|
|
370
|
+
) -> None:
|
|
371
|
+
"""Display the workflow execution plan using clean UI."""
|
|
372
|
+
self.console.print(f"\n[bold cyan]🚀 Starting workflow: {name}[/bold cyan]")
|
|
373
|
+
self.console.print(f"[dim]Will execute {len(steps)} steps...[/dim]\n")
|
|
374
|
+
|
|
375
|
+
def _check_dependencies(
|
|
376
|
+
self, step: WorkflowStep, history: List[WorkflowStep]
|
|
377
|
+
) -> bool:
|
|
378
|
+
"""Check if all dependencies for a step are satisfied."""
|
|
379
|
+
if not step.dependencies:
|
|
380
|
+
return True
|
|
381
|
+
|
|
382
|
+
completed_steps = {
|
|
383
|
+
s.name for s in history if s.status == WorkflowStatus.COMPLETED
|
|
384
|
+
}
|
|
385
|
+
return all(dep in completed_steps for dep in step.dependencies)
|
|
386
|
+
|
|
387
|
+
async def _request_approval(self, step: WorkflowStep) -> bool:
|
|
388
|
+
"""Request approval for a step that requires it."""
|
|
389
|
+
self.console.print(f"\n[yellow]⚠ Step '{step.name}' requires approval[/yellow]")
|
|
390
|
+
self.console.print(f"Description: {step.description}")
|
|
391
|
+
|
|
392
|
+
# Use the approval manager if available
|
|
393
|
+
if self.approval_manager and hasattr(self.approval_manager, "request_approval"):
|
|
394
|
+
# Create a basic operation object for the approval manager
|
|
395
|
+
from .types import Operation, OperationType
|
|
396
|
+
|
|
397
|
+
operation = Operation(
|
|
398
|
+
type=OperationType.WORKFLOW_STEP,
|
|
399
|
+
description=step.description,
|
|
400
|
+
data={"step_name": step.name, "description": step.description},
|
|
401
|
+
requires_approval=True,
|
|
402
|
+
)
|
|
403
|
+
approved = await self.approval_manager.request_approval(operation)
|
|
404
|
+
if approved:
|
|
405
|
+
self.console.print("[green]✓ Approved[/green]")
|
|
406
|
+
else:
|
|
407
|
+
self.console.print("[red]✗ Denied[/red]")
|
|
408
|
+
return approved
|
|
409
|
+
|
|
410
|
+
# Default behavior for demo/test purposes
|
|
411
|
+
await asyncio.sleep(0.5) # Simulate approval delay
|
|
412
|
+
self.console.print("[green]✓ Approved[/green]")
|
|
413
|
+
return True
|
|
414
|
+
|
|
415
|
+
def _display_step_result(self, step: WorkflowStep) -> None:
|
|
416
|
+
"""Display the result of a completed step."""
|
|
417
|
+
status_symbol = "✓" if step.status == WorkflowStatus.COMPLETED else "✗"
|
|
418
|
+
status_color = "green" if step.status == WorkflowStatus.COMPLETED else "red"
|
|
419
|
+
|
|
420
|
+
self.console.print(
|
|
421
|
+
f"[{status_color}]{status_symbol}[/{status_color}] {step.name}: {step.description}"
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
if step.error:
|
|
425
|
+
self.console.print(f" [red]Error: {step.error}[/red]")
|
|
426
|
+
|
|
427
|
+
async def _display_workflow_summary(self) -> None:
|
|
428
|
+
"""Display a clean summary of the workflow execution."""
|
|
429
|
+
completed = sum(
|
|
430
|
+
1 for s in self.context.history if s.status == WorkflowStatus.COMPLETED
|
|
431
|
+
)
|
|
432
|
+
failed = sum(
|
|
433
|
+
1 for s in self.context.history if s.status == WorkflowStatus.FAILED
|
|
434
|
+
)
|
|
435
|
+
total = len(self.context.history)
|
|
436
|
+
|
|
437
|
+
if failed == 0:
|
|
438
|
+
self.console.print(
|
|
439
|
+
f"\n[bold green]✅ Workflow completed successfully![/bold green]"
|
|
440
|
+
)
|
|
441
|
+
else:
|
|
442
|
+
self.console.print(
|
|
443
|
+
f"\n[yellow]⚠️ Workflow completed with {failed} issues[/yellow]"
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
self.console.print(f"[dim]Executed {completed}/{total} steps[/dim]")
|
|
447
|
+
|
|
448
|
+
def _get_progress_operation_type(
|
|
449
|
+
self, workflow_step_type: WorkflowStepType
|
|
450
|
+
) -> ProgressOperationType:
|
|
451
|
+
"""Map workflow step types to progress indicator operation types."""
|
|
452
|
+
type_mapping = {
|
|
453
|
+
WorkflowStepType.READ_FILE: ProgressOperationType.READ,
|
|
454
|
+
WorkflowStepType.WRITE_FILE: ProgressOperationType.WRITE,
|
|
455
|
+
WorkflowStepType.ANALYZE: ProgressOperationType.ANALYZE,
|
|
456
|
+
WorkflowStepType.VALIDATE: ProgressOperationType.VALIDATE,
|
|
457
|
+
WorkflowStepType.CUSTOM: ProgressOperationType.OTHER,
|
|
458
|
+
}
|
|
459
|
+
return type_mapping.get(workflow_step_type, ProgressOperationType.OTHER)
|
|
460
|
+
|
|
461
|
+
# Built-in action implementations
|
|
462
|
+
|
|
463
|
+
async def _list_directory_action(
|
|
464
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
465
|
+
) -> List[str]:
|
|
466
|
+
"""List directory contents."""
|
|
467
|
+
path = Path(params.get("path", "."))
|
|
468
|
+
files = []
|
|
469
|
+
|
|
470
|
+
context.console.print(f"\n[cyan]Listing directory: {path}[/cyan]")
|
|
471
|
+
|
|
472
|
+
for item in path.iterdir():
|
|
473
|
+
if item.is_dir():
|
|
474
|
+
files.append(f"📁 {item.name}/")
|
|
475
|
+
else:
|
|
476
|
+
files.append(f"📄 {item.name}")
|
|
477
|
+
|
|
478
|
+
# Display first 10 items
|
|
479
|
+
for file in files[:10]:
|
|
480
|
+
context.console.print(f" {file}")
|
|
481
|
+
|
|
482
|
+
if len(files) > 10:
|
|
483
|
+
context.console.print(f" ... and {len(files) - 10} more items")
|
|
484
|
+
|
|
485
|
+
context.set("project_files", files)
|
|
486
|
+
return files
|
|
487
|
+
|
|
488
|
+
async def _detect_tech_stack_action(
|
|
489
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
490
|
+
) -> Dict[str, Any]:
|
|
491
|
+
"""Detect technology stack from project files."""
|
|
492
|
+
context.console.print("\n[cyan]Detecting technology stack...[/cyan]")
|
|
493
|
+
|
|
494
|
+
tech_stack = {}
|
|
495
|
+
files = context.get("project_files", [])
|
|
496
|
+
|
|
497
|
+
# Check for common tech indicators
|
|
498
|
+
file_names = [f.replace("📄 ", "").replace("📁 ", "").strip("/") for f in files]
|
|
499
|
+
|
|
500
|
+
if "package.json" in file_names:
|
|
501
|
+
tech_stack["javascript"] = "Node.js/npm"
|
|
502
|
+
context.console.print(" ✓ Found: Node.js project (package.json)")
|
|
503
|
+
|
|
504
|
+
if (
|
|
505
|
+
"requirements.txt" in file_names
|
|
506
|
+
or "setup.py" in file_names
|
|
507
|
+
or "pyproject.toml" in file_names
|
|
508
|
+
):
|
|
509
|
+
tech_stack["python"] = "Python/pip"
|
|
510
|
+
context.console.print(" ✓ Found: Python project")
|
|
511
|
+
|
|
512
|
+
if "Cargo.toml" in file_names:
|
|
513
|
+
tech_stack["rust"] = "Rust/Cargo"
|
|
514
|
+
context.console.print(" ✓ Found: Rust project")
|
|
515
|
+
|
|
516
|
+
if ".git" in file_names:
|
|
517
|
+
tech_stack["vcs"] = "Git"
|
|
518
|
+
context.console.print(" ✓ Found: Git repository")
|
|
519
|
+
|
|
520
|
+
if ".mcp.json" in file_names:
|
|
521
|
+
tech_stack["mcp"] = "Model Context Protocol"
|
|
522
|
+
context.console.print(" ✓ Found: MCP server configuration")
|
|
523
|
+
|
|
524
|
+
# Check for Omnimancer specific patterns
|
|
525
|
+
if any("omnimancer" in f.lower() for f in file_names):
|
|
526
|
+
tech_stack["omnimancer"] = "Omnimancer CLI Framework"
|
|
527
|
+
context.console.print(" ✓ Found: Omnimancer framework")
|
|
528
|
+
|
|
529
|
+
context.set("tech_stack", tech_stack)
|
|
530
|
+
return tech_stack
|
|
531
|
+
|
|
532
|
+
async def _check_configuration_action(
|
|
533
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
534
|
+
) -> Dict[str, Any]:
|
|
535
|
+
"""Check for configuration files."""
|
|
536
|
+
context.console.print("\n[cyan]Checking configuration files...[/cyan]")
|
|
537
|
+
|
|
538
|
+
config_files = {}
|
|
539
|
+
files = context.get("project_files", [])
|
|
540
|
+
file_names = [f.replace("📄 ", "").replace("📁 ", "").strip("/") for f in files]
|
|
541
|
+
|
|
542
|
+
config_patterns = {
|
|
543
|
+
".env": "Environment variables",
|
|
544
|
+
"config.json": "JSON configuration",
|
|
545
|
+
"config.yaml": "YAML configuration",
|
|
546
|
+
".gitignore": "Git ignore rules",
|
|
547
|
+
"Dockerfile": "Docker configuration",
|
|
548
|
+
".github": "GitHub workflows",
|
|
549
|
+
".mcp.json": "MCP server configuration",
|
|
550
|
+
"pyproject.toml": "Python project configuration",
|
|
551
|
+
".taskmaster": "Task Master AI configuration",
|
|
552
|
+
".claude": "Claude Code configuration",
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
for pattern, description in config_patterns.items():
|
|
556
|
+
if pattern in file_names:
|
|
557
|
+
config_files[pattern] = description
|
|
558
|
+
context.console.print(f" ✓ Found: {description} ({pattern})")
|
|
559
|
+
|
|
560
|
+
context.set("config_files", config_files)
|
|
561
|
+
return config_files
|
|
562
|
+
|
|
563
|
+
async def _analyze_structure_action(
|
|
564
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
565
|
+
) -> Dict[str, Any]:
|
|
566
|
+
"""Analyze project structure."""
|
|
567
|
+
context.console.print("\n[cyan]Analyzing project structure...[/cyan]")
|
|
568
|
+
|
|
569
|
+
analysis = {"type": "Unknown", "patterns": []}
|
|
570
|
+
|
|
571
|
+
tech_stack = context.get("tech_stack", {})
|
|
572
|
+
|
|
573
|
+
if "python" in tech_stack:
|
|
574
|
+
analysis["type"] = "Python Application"
|
|
575
|
+
analysis["patterns"].append("Python package structure detected")
|
|
576
|
+
context.console.print(" ✓ Identified as Python application")
|
|
577
|
+
|
|
578
|
+
if "javascript" in tech_stack:
|
|
579
|
+
analysis["type"] = "Node.js Application"
|
|
580
|
+
analysis["patterns"].append("Node.js project structure detected")
|
|
581
|
+
context.console.print(" ✓ Identified as Node.js application")
|
|
582
|
+
|
|
583
|
+
context.set("structure_analysis", analysis)
|
|
584
|
+
return analysis
|
|
585
|
+
|
|
586
|
+
async def _generate_summary_action(
|
|
587
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
588
|
+
) -> str:
|
|
589
|
+
"""Generate a summary of the analysis."""
|
|
590
|
+
context.console.print("\n[cyan]Generating analysis summary...[/cyan]")
|
|
591
|
+
|
|
592
|
+
tech_stack = context.get("tech_stack", {})
|
|
593
|
+
config_files = context.get("config_files", {})
|
|
594
|
+
analysis = context.get("structure_analysis", {})
|
|
595
|
+
|
|
596
|
+
summary = f"""
|
|
597
|
+
### Project Analysis Complete
|
|
598
|
+
|
|
599
|
+
**Project Type:** {analysis.get('type', 'Unknown')}
|
|
600
|
+
|
|
601
|
+
**Technology Stack:**
|
|
602
|
+
{chr(10).join(f"- {tech}: {desc}" for tech, desc in tech_stack.items())}
|
|
603
|
+
|
|
604
|
+
**Configuration Files:**
|
|
605
|
+
{chr(10).join(f"- {file}: {desc}" for file, desc in config_files.items())}
|
|
606
|
+
|
|
607
|
+
**Patterns Detected:**
|
|
608
|
+
{chr(10).join(f"- {pattern}" for pattern in analysis.get('patterns', []))}
|
|
609
|
+
"""
|
|
610
|
+
|
|
611
|
+
context.console.print(
|
|
612
|
+
Panel(
|
|
613
|
+
Markdown(summary),
|
|
614
|
+
title="[bold]Analysis Summary[/bold]",
|
|
615
|
+
border_style="green",
|
|
616
|
+
)
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
context.set("summary", summary)
|
|
620
|
+
return summary
|
|
621
|
+
|
|
622
|
+
async def _read_file_action(
|
|
623
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
624
|
+
) -> str:
|
|
625
|
+
"""Read file content."""
|
|
626
|
+
file_path = params.get("file_path")
|
|
627
|
+
if not file_path:
|
|
628
|
+
raise ValueError("file_path parameter required")
|
|
629
|
+
|
|
630
|
+
if self.file_system:
|
|
631
|
+
content = await self.file_system.read_file(file_path)
|
|
632
|
+
context.set("original_content", content)
|
|
633
|
+
return content
|
|
634
|
+
return ""
|
|
635
|
+
|
|
636
|
+
async def _prepare_changes_action(
|
|
637
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
638
|
+
) -> Dict[str, Any]:
|
|
639
|
+
"""Prepare file changes."""
|
|
640
|
+
original = context.get("original_content", "")
|
|
641
|
+
changes = params.get("changes", {})
|
|
642
|
+
|
|
643
|
+
# Prepare the modified content
|
|
644
|
+
modified = changes.get("content", original)
|
|
645
|
+
|
|
646
|
+
context.set("modified_content", modified)
|
|
647
|
+
context.set("changes", changes)
|
|
648
|
+
|
|
649
|
+
return {"original": original, "modified": modified}
|
|
650
|
+
|
|
651
|
+
async def _show_diff_action(
|
|
652
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
653
|
+
) -> None:
|
|
654
|
+
"""Show diff for review."""
|
|
655
|
+
context.get("original_content", "")
|
|
656
|
+
context.get("modified_content", "")
|
|
657
|
+
|
|
658
|
+
# In a real implementation, this would use the diff renderer
|
|
659
|
+
context.console.print("\n[yellow]Changes to review:[/yellow]")
|
|
660
|
+
context.console.print("(Diff display would appear here)")
|
|
661
|
+
|
|
662
|
+
async def _write_file_action(
|
|
663
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
664
|
+
) -> bool:
|
|
665
|
+
"""Write file content."""
|
|
666
|
+
file_path = params.get("file_path")
|
|
667
|
+
content = context.get("modified_content", "")
|
|
668
|
+
|
|
669
|
+
if not file_path:
|
|
670
|
+
raise ValueError("file_path parameter required")
|
|
671
|
+
|
|
672
|
+
if self.file_system:
|
|
673
|
+
await self.file_system.write_file(file_path, content)
|
|
674
|
+
return True
|
|
675
|
+
return False
|
|
676
|
+
|
|
677
|
+
async def _validate_changes_action(
|
|
678
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
679
|
+
) -> bool:
|
|
680
|
+
"""Validate applied changes."""
|
|
681
|
+
# In a real implementation, this would verify the changes were applied correctly
|
|
682
|
+
context.console.print("[green]✓ Changes validated successfully[/green]")
|
|
683
|
+
return True
|
|
684
|
+
|
|
685
|
+
# General Action Workflow Methods
|
|
686
|
+
|
|
687
|
+
async def _understand_request_action(
|
|
688
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
689
|
+
) -> Dict[str, Any]:
|
|
690
|
+
"""Understand and analyze the user's request."""
|
|
691
|
+
user_request = params.get("user_request", context.get("user_request", ""))
|
|
692
|
+
|
|
693
|
+
# Simulate analyzing the request
|
|
694
|
+
context.console.print(f"[cyan]📝 Analyzing request: '{user_request}'[/cyan]")
|
|
695
|
+
|
|
696
|
+
# Parse the request to understand intent and extract key information
|
|
697
|
+
analysis = {
|
|
698
|
+
"original_request": user_request,
|
|
699
|
+
"intent": "general_action",
|
|
700
|
+
"complexity": "medium",
|
|
701
|
+
"estimated_steps": 3,
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
# Store analysis in context for next steps
|
|
705
|
+
context.set("request_analysis", analysis)
|
|
706
|
+
return analysis
|
|
707
|
+
|
|
708
|
+
async def _plan_approach_action(
|
|
709
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
710
|
+
) -> Dict[str, Any]:
|
|
711
|
+
"""Plan the approach to fulfill the user's request."""
|
|
712
|
+
analysis = context.get("request_analysis", {})
|
|
713
|
+
user_request = analysis.get("original_request", "")
|
|
714
|
+
|
|
715
|
+
context.console.print(f"[cyan]🎯 Planning approach for: {user_request}[/cyan]")
|
|
716
|
+
|
|
717
|
+
# Create a basic plan based on the request
|
|
718
|
+
plan = {
|
|
719
|
+
"approach": "autonomous_execution",
|
|
720
|
+
"steps": [
|
|
721
|
+
"Prepare AI prompt with user request",
|
|
722
|
+
"Execute action using agent capabilities",
|
|
723
|
+
"Capture and process results",
|
|
724
|
+
"Verify completion",
|
|
725
|
+
],
|
|
726
|
+
"requires_approval": False,
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
context.set("execution_plan", plan)
|
|
730
|
+
return plan
|
|
731
|
+
|
|
732
|
+
async def _execute_action(
|
|
733
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
734
|
+
) -> Dict[str, Any]:
|
|
735
|
+
"""Execute the planned action autonomously."""
|
|
736
|
+
user_request = context.get("user_request", "")
|
|
737
|
+
|
|
738
|
+
context.console.print(f"[cyan]🚀 Executing autonomous action...[/cyan]")
|
|
739
|
+
|
|
740
|
+
# Actually execute the user request with AI provider if available
|
|
741
|
+
try:
|
|
742
|
+
# Send the request to AI with agent capabilities enabled
|
|
743
|
+
if hasattr(context, "engine") and context.engine:
|
|
744
|
+
# The agent engine inherits from core engine which has send_message
|
|
745
|
+
response = await context.engine.send_message(user_request)
|
|
746
|
+
|
|
747
|
+
if response.is_success:
|
|
748
|
+
result = {
|
|
749
|
+
"status": "completed",
|
|
750
|
+
"action_taken": f"AI processed request: {user_request}",
|
|
751
|
+
"details": response.content,
|
|
752
|
+
"ai_response": response.content,
|
|
753
|
+
"timestamp": "just now",
|
|
754
|
+
}
|
|
755
|
+
else:
|
|
756
|
+
result = {
|
|
757
|
+
"status": "failed",
|
|
758
|
+
"action_taken": f"Failed to process: {user_request}",
|
|
759
|
+
"details": f"Error: {response.error}",
|
|
760
|
+
"error": response.error,
|
|
761
|
+
"timestamp": "just now",
|
|
762
|
+
}
|
|
763
|
+
else:
|
|
764
|
+
# Fallback: simulate execution
|
|
765
|
+
result = {
|
|
766
|
+
"status": "completed",
|
|
767
|
+
"action_taken": f"Processed request: {user_request}",
|
|
768
|
+
"details": "Action executed using autonomous workflow system (simulated)",
|
|
769
|
+
"timestamp": "just now",
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
except Exception as e:
|
|
773
|
+
result = {
|
|
774
|
+
"status": "failed",
|
|
775
|
+
"action_taken": f"Error processing: {user_request}",
|
|
776
|
+
"details": f"Exception: {str(e)}",
|
|
777
|
+
"error": str(e),
|
|
778
|
+
"timestamp": "just now",
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
context.set("execution_result", result)
|
|
782
|
+
return result
|
|
783
|
+
|
|
784
|
+
async def _verify_results_action(
|
|
785
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
786
|
+
) -> bool:
|
|
787
|
+
"""Verify that the action was completed successfully."""
|
|
788
|
+
result = context.get("execution_result", {})
|
|
789
|
+
|
|
790
|
+
context.console.print("[cyan]✅ Verifying action completion...[/cyan]")
|
|
791
|
+
|
|
792
|
+
# Check if execution was successful
|
|
793
|
+
success = result.get("status") == "completed"
|
|
794
|
+
|
|
795
|
+
if success:
|
|
796
|
+
context.console.print("[green]✓ Action completed successfully[/green]")
|
|
797
|
+
else:
|
|
798
|
+
context.console.print("[red]✗ Action may not have completed fully[/red]")
|
|
799
|
+
|
|
800
|
+
context.set("verification_success", success)
|
|
801
|
+
return success
|
|
802
|
+
|
|
803
|
+
async def _provide_summary_action(
|
|
804
|
+
self, context: WorkflowContext, params: Dict[str, Any]
|
|
805
|
+
) -> str:
|
|
806
|
+
"""Provide a summary of what was accomplished."""
|
|
807
|
+
user_request = context.get("user_request", "")
|
|
808
|
+
result = context.get("execution_result", {})
|
|
809
|
+
success = context.get("verification_success", False)
|
|
810
|
+
|
|
811
|
+
if success:
|
|
812
|
+
if "ai_response" in result:
|
|
813
|
+
# Don't show summary if we have the actual AI response - it will be shown in interface
|
|
814
|
+
summary = f"✅ Successfully completed: {user_request}"
|
|
815
|
+
context.console.print(f"[bold green]📋 Summary:[/bold green] {summary}")
|
|
816
|
+
else:
|
|
817
|
+
summary = f"✅ Successfully completed: {user_request}\n\nAction taken: {result.get('action_taken', 'Autonomous workflow execution')}"
|
|
818
|
+
context.console.print(
|
|
819
|
+
f"[bold green]📋 Summary:[/bold green]\n{summary}"
|
|
820
|
+
)
|
|
821
|
+
else:
|
|
822
|
+
summary = f"⚠️ Partially completed: {user_request}\n\nStatus: Some issues may have occurred during execution"
|
|
823
|
+
context.console.print(f"[bold yellow]📋 Summary:[/bold yellow]\n{summary}")
|
|
824
|
+
|
|
825
|
+
context.set("final_summary", summary)
|
|
826
|
+
return summary
|