diff --git a/conductor/tracks/gui_sim_extension_20260224/plan.md b/conductor/tracks/gui_sim_extension_20260224/plan.md index d49fb20..7c277cd 100644 --- a/conductor/tracks/gui_sim_extension_20260224/plan.md +++ b/conductor/tracks/gui_sim_extension_20260224/plan.md @@ -19,7 +19,7 @@ - [x] Task: Conductor - User Manual Verification 'Phase 3: AI Settings and Tools Simulation' (Protocol in workflow.md) s1t2u3v ## Phase 4: Execution and Modals Simulation -- [ ] Task: Create the test script `sim_execution.py`. +- [~] Task: Create the test script `sim_execution.py`. - [ ] Task: Simulate the AI generating a PowerShell script that triggers the explicit confirmation modal. - [ ] Task: Assert the modal appears correctly and accepts input/approval from the simulated user. - [ ] Task: Validate the executed output via API hooks. diff --git a/gui_2.py b/gui_2.py index b2ca899..11a3654 100644 --- a/gui_2.py +++ b/gui_2.py @@ -270,13 +270,16 @@ class App: 'current_provider': 'current_provider', 'current_model': 'current_model', 'token_budget_pct': '_token_budget_pct', - 'token_budget_label': '_token_budget_label' + 'token_budget_label': '_token_budget_label', + 'show_confirm_modal': 'show_confirm_modal' } self._clickable_actions = { 'btn_reset': self._handle_reset_session, 'btn_gen_send': self._handle_generate_send, 'btn_md_only': self._handle_md_only, + 'btn_approve_script': self._handle_approve_script, + 'btn_reject_script': self._handle_reject_script, 'btn_project_save': self._cb_project_save, 'btn_disc_create': self._cb_disc_create, } @@ -537,6 +540,20 @@ class App: except Exception as e: print(f"Error executing GUI task: {e}") + def _handle_approve_script(self): + """Logic for approving a pending script.""" + if self.show_confirm_modal: + self.show_confirm_modal = False + if self.pending_script_callback: + self.pending_script_callback(True) + + def _handle_reject_script(self): + """Logic for rejecting a pending script.""" + if self.show_confirm_modal: + self.show_confirm_modal = False + if self.pending_script_callback: + self.pending_script_callback(False) + def _handle_reset_session(self): """Logic for resetting the AI session.""" ai_client.reset_session() diff --git a/simulation/sim_execution.py b/simulation/sim_execution.py new file mode 100644 index 0000000..3d7dd35 --- /dev/null +++ b/simulation/sim_execution.py @@ -0,0 +1,47 @@ +import sys +import os +import time +from simulation.sim_base import BaseSimulation, run_sim + +class ExecutionSimulation(BaseSimulation): + def run(self): + print("\n--- Running Execution & Modals Simulation ---") + + # 1. Trigger script generation + msg = "Create a hello.ps1 script that prints 'Simulation Test' and execute it." + print(f"[Sim] Sending message to trigger script: {msg}") + self.sim.run_discussion_turn(msg) + + # 2. Wait for confirmation modal + print("[Sim] Waiting for confirmation modal...") + modal_shown = False + for i in range(30): + if self.client.get_value("show_confirm_modal"): + modal_shown = True + print(f"[Sim] Modal shown at second {i}") + break + time.sleep(1) + + assert modal_shown, "Expected confirmation modal to be shown" + + # 3. Approve script + print("[Sim] Approving script execution...") + self.client.click("btn_approve_script") + time.sleep(2) + + # 4. Verify output in history or status + session = self.client.get_session() + entries = session.get('session', {}).get('entries', []) + + # Tool outputs are usually in history + success = any("Simulation Test" in e.get('content', '') for e in entries if e.get('role') in ['Tool', 'Function']) + if success: + print("[Sim] Output found in session history.") + else: + print("[Sim] Output NOT found in history yet, checking status...") + # Maybe check ai_status + status = self.client.get_value("ai_status") + print(f"[Sim] Final Status: {status}") + +if __name__ == "__main__": + run_sim(ExecutionSimulation) diff --git a/tests/test_sim_execution.py b/tests/test_sim_execution.py new file mode 100644 index 0000000..eaa6b84 --- /dev/null +++ b/tests/test_sim_execution.py @@ -0,0 +1,52 @@ +import pytest +from unittest.mock import MagicMock, patch +import os +import sys + +# Ensure project root is in path +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from simulation.sim_execution import ExecutionSimulation + +def test_execution_simulation_run(): + mock_client = MagicMock() + mock_client.wait_for_server.return_value = True + + # Mock show_confirm_modal state + vals = {"show_confirm_modal": False} + def side_effect(key): + return vals.get(key) + def set_side_effect(key, val): + vals[key] = val + + mock_client.get_value.side_effect = side_effect + mock_client.set_value.side_effect = set_side_effect + + # Mock session entries with tool output + mock_session = { + 'session': { + 'entries': [ + {'role': 'Tool', 'content': 'Simulation Test', 'tool_call_id': 'call_1'} + ] + } + } + mock_client.get_session.return_value = mock_session + + with patch('simulation.sim_base.WorkflowSimulator') as mock_sim_class: + mock_sim = MagicMock() + mock_sim_class.return_value = mock_sim + + # We need a way to trigger show_confirm_modal = True + # In sim_execution.py, it's called after run_discussion_turn + # I'll mock run_discussion_turn to set it + def run_side_effect(msg): + vals["show_confirm_modal"] = True + + mock_sim.run_discussion_turn.side_effect = run_side_effect + + sim = ExecutionSimulation(mock_client) + sim.run() + + # Verify calls + mock_sim.run_discussion_turn.assert_called() + mock_client.click.assert_called_with("btn_approve_script")