377 lines
29 KiB
Python
377 lines
29 KiB
Python
"""
|
|
API Hook Client - Python client for the Hook API.
|
|
|
|
This module provides a Python client for interacting with the Hook API exposed by the application on port 8999.
|
|
It is used for:
|
|
- Automated GUI testing via the `live_gui` pytest fixture
|
|
- External tool integration
|
|
- Remote control of the application
|
|
|
|
Architecture:
|
|
- Uses requests library for HTTP communication
|
|
- All methods return dict[str, Any] or None
|
|
- Handles connection errors gracefully (returns None on failure)
|
|
|
|
Key Method Categories:
|
|
1. Connection: wait_for_server, get_status
|
|
2. State Query: get_project, get_session. get_performance, get_mma_status
|
|
3. GUI Manipulation: click, set_value, select_tab, select_list_item
|
|
4. Polling: wait_for_event
|
|
5. HITL: request_confirmation
|
|
|
|
Timeout Handling:
|
|
- Standard operations: 5s timeout
|
|
- HITL dialogs: 60s timeout (waits for human input)
|
|
|
|
Integration:
|
|
- Used by simulation tests (tests/visual_sim_mma_v2.py)
|
|
- Used by external tools for automation
|
|
|
|
See Also:
|
|
- src/api_hooks.py for the server implementation
|
|
- docs/guide_tools.md for Hook API documentation
|
|
"""
|
|
from __future__ import annotations
|
|
import requests # type: ignore[import-untyped]
|
|
import time
|
|
from typing import Any
|
|
|
|
class ApiHookClient:
|
|
def __init__(self, base_url: str = "http://127.0.0.1:8999", api_key: str | None = None):
|
|
"""
|
|
[C: src/mcp_client.py:_DDGParser.__init__, src/mcp_client.py:_TextExtractor.__init__]
|
|
"""
|
|
self.base_url = base_url.rstrip('/')
|
|
self.api_key = api_key
|
|
|
|
def _make_request(self, method: str, path: str, data: dict | None = None, timeout: float = 5.0) -> dict[str, Any] | None:
|
|
"""
|
|
Helper to make HTTP requests to the hook server.
|
|
[C: tests/test_api_hook_client.py:test_unsupported_method_error]
|
|
"""
|
|
url = f"{self.base_url}{path}"
|
|
headers = {}
|
|
if self.api_key:
|
|
headers["X-API-KEY"] = self.api_key
|
|
if method not in ('GET', 'POST', 'DELETE'):
|
|
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
try:
|
|
if method == 'GET':
|
|
response = requests.get(url, headers=headers, timeout=timeout)
|
|
elif method == 'POST':
|
|
response = requests.post(url, json=data, headers=headers, timeout=timeout)
|
|
elif method == 'DELETE':
|
|
response = requests.delete(url, headers=headers, timeout=timeout)
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
return None
|
|
except Exception:
|
|
# Silently ignore connection errors unless we are in a wait loop
|
|
return None
|
|
|
|
def wait_for_server(self, timeout: int = 15) -> bool:
|
|
"""
|
|
Polls the health endpoint until the server responds or timeout occurs.
|
|
[C: simulation/live_walkthrough.py:main, simulation/ping_pong.py:main, simulation/sim_base.py:BaseSimulation.setup, tests/smoke_status_hook.py:test_status_hook, tests/test_ai_settings_layout.py:test_change_provider_via_hook, tests/test_ai_settings_layout.py:test_set_params_via_custom_callback, tests/test_auto_switch_sim.py:test_auto_switch_sim, tests/test_conductor_api_hook_integration.py:test_conductor_integrates_api_hook_client_for_verification, tests/test_deepseek_infra.py:test_gui_provider_list_via_hooks, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_external_editor_gui.py:test_button_click_is_received, tests/test_external_editor_gui.py:test_patch_modal_shows_with_configured_editor, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui2_parity.py:test_gui2_click_hook_works, tests/test_gui2_parity.py:test_gui2_custom_callback_hook_works, tests/test_gui2_parity.py:test_gui2_set_value_hook_works, tests/test_gui_context_presets.py:test_gui_context_preset_save_load, tests/test_hooks.py:test_live_hook_server_responses, tests/test_live_workflow.py:test_full_live_workflow, tests/test_mma_concurrent_tracks_sim.py:test_mma_concurrent_tracks_execution, tests/test_mma_concurrent_tracks_stress_sim.py:test_mma_concurrent_tracks_stress, tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow, tests/test_patch_modal_gui.py:test_patch_apply_modal_workflow, tests/test_patch_modal_gui.py:test_patch_modal_appears_on_trigger, tests/test_preset_windows_layout.py:test_api_hook_under_load, tests/test_preset_windows_layout.py:test_preset_windows_opening, tests/test_rag_phase4_final_verify.py:test_phase4_final_verify, tests/test_rag_phase4_stress.py:test_rag_large_codebase_verification_sim, tests/test_rag_visual_sim.py:test_rag_full_lifecycle_sim, tests/test_rag_visual_sim.py:test_rag_settings_persistence_sim, tests/test_selectable_ui.py:test_selectable_label_stability, tests/test_system_prompt_sim.py:test_system_prompt_sim, tests/test_tool_management_layout.py:test_tool_management_gettable_fields, tests/test_tool_management_layout.py:test_tool_management_state_updates, tests/test_ui_cache_controls_sim.py:test_ui_cache_controls, tests/test_undo_redo_sim.py:test_undo_redo_context_mutation, tests/test_undo_redo_sim.py:test_undo_redo_discussion_mutation, tests/test_undo_redo_sim.py:test_undo_redo_lifecycle, tests/test_visual_orchestration.py:test_mma_epic_lifecycle, tests/test_visual_sim_gui_ux.py:test_gui_track_creation, tests/test_visual_sim_gui_ux.py:test_gui_ux_event_routing, tests/test_visual_sim_mma_v2.py:test_mma_complete_lifecycle, tests/test_workspace_profiles_sim.py:test_workspace_profiles_restoration, tests/test_z_negative_flows.py:test_mock_error_result, tests/test_z_negative_flows.py:test_mock_malformed_json, tests/test_z_negative_flows.py:test_mock_timeout]
|
|
"""
|
|
start = time.time()
|
|
while time.time() - start < timeout:
|
|
status = self.get_status()
|
|
if status and (status.get("status") == "ok" or "status" in status):
|
|
return True
|
|
time.sleep(0.5)
|
|
return False
|
|
|
|
def get_status(self) -> dict[str, Any]:
|
|
"""
|
|
Checks the health of the hook server.
|
|
[C: tests/test_api_hook_client.py:test_get_status_success, tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation, tests/test_hooks.py:test_live_hook_server_responses, tests/test_mma_concurrent_tracks_stress_sim.py:test_mma_concurrent_tracks_stress, tests/test_preset_windows_layout.py:make_request, tests/test_preset_windows_layout.py:test_preset_windows_opening, tests/test_ui_cache_controls_sim.py:test_ui_cache_controls]
|
|
"""
|
|
res = self._make_request('GET', '/status')
|
|
if res is None:
|
|
# For backward compatibility with tests expecting ConnectionError
|
|
# But our _make_request handles it. Let's return empty if failed.
|
|
return {}
|
|
return res
|
|
|
|
def post_project(self, project_data: dict) -> dict[str, Any]:
|
|
"""
|
|
Updates the current project configuration.
|
|
[C: simulation/sim_context.py:ContextSimulation.run]
|
|
"""
|
|
return self._make_request('POST', '/api/project', data=project_data) or {}
|
|
|
|
def get_project(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves the current project state.
|
|
[C: simulation/sim_context.py:ContextSimulation.run, tests/test_api_hook_client.py:test_get_project_success, tests/test_gui_context_presets.py:test_gui_context_preset_save_load, tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation, tests/test_hooks.py:test_live_hook_server_responses, tests/test_live_workflow.py:test_full_live_workflow]
|
|
"""
|
|
return self._make_request('GET', '/api/project') or {}
|
|
|
|
def get_session(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves the current discussion session history.
|
|
[C: simulation/ping_pong.py:main, simulation/sim_context.py:ContextSimulation.run, simulation/sim_execution.py:ExecutionSimulation.run, simulation/sim_tools.py:ToolsSimulation.run, simulation/workflow_sim.py:WorkflowSimulator.run_discussion_turn_async, simulation/workflow_sim.py:WorkflowSimulator.wait_for_ai_response, tests/test_api_hook_client.py:test_get_session_success, tests/test_gui_stress_performance.py:test_comms_volume_stress_performance, tests/test_live_workflow.py:test_full_live_workflow, tests/test_rag_phase4_final_verify.py:test_phase4_final_verify, tests/test_rag_phase4_stress.py:test_rag_large_codebase_verification_sim]
|
|
"""
|
|
return self._make_request('GET', '/api/session') or {}
|
|
|
|
def post_session(self, session_entries: list[dict]) -> dict[str, Any]:
|
|
"""
|
|
Updates the session history.
|
|
[C: tests/test_gui_stress_performance.py:test_comms_volume_stress_performance, tests/test_live_workflow.py:test_full_live_workflow]
|
|
"""
|
|
return self._make_request('POST', '/api/session', data={"session": {"entries": session_entries}}) or {}
|
|
|
|
def get_events(self) -> list[dict[str, Any]]:
|
|
"""Retrieves any pending events from the API event queue."""
|
|
res = self._make_request('GET', '/api/events')
|
|
return res.get("events", []) if res else []
|
|
|
|
def clear_events(self) -> list[dict[str, Any]]:
|
|
"""
|
|
Retrieves and clears the event queue.
|
|
[C: simulation/sim_base.py:BaseSimulation.setup]
|
|
"""
|
|
return self.get_events()
|
|
|
|
|
|
def wait_for_event(self, event_type: str, timeout: int = 5) -> dict[str, Any] | None:
|
|
"""
|
|
[C: simulation/sim_base.py:BaseSimulation.wait_for_event, simulation/sim_execution.py:ExecutionSimulation.run, tests/test_z_negative_flows.py:test_mock_error_result, tests/test_z_negative_flows.py:test_mock_malformed_json, tests/test_z_negative_flows.py:test_mock_timeout]
|
|
"""
|
|
start = time.time()
|
|
while time.time() - start < timeout:
|
|
events = self.get_events()
|
|
for ev in events:
|
|
if ev.get("type") == event_type or ev.get("event_type") == event_type:
|
|
return ev
|
|
time.sleep(0.2)
|
|
return None
|
|
|
|
def post_gui(self, payload: dict) -> dict[str, Any]:
|
|
"""
|
|
Pushes an event to the GUI's AsyncEventQueue via the /api/gui endpoint.
|
|
[C: tests/test_ai_settings_layout.py:test_set_params_via_custom_callback, tests/test_api_hook_client.py:test_post_gui_success, tests/test_gui2_parity.py:test_gui2_custom_callback_hook_works, tests/test_gui2_parity.py:test_gui2_set_value_hook_works, tests/test_visual_mma.py:test_visual_mma_components]
|
|
"""
|
|
return self._make_request('POST', '/api/gui', data=payload) or {}
|
|
|
|
def push_event(self, action: str, payload: dict) -> dict[str, Any]:
|
|
"""
|
|
Convenience to push a GUI task.
|
|
[C: tests/test_auto_switch_sim.py:test_auto_switch_sim, tests/test_auto_switch_sim.py:trigger_tier, tests/test_external_editor_gui.py:test_button_click_is_received, tests/test_external_editor_gui.py:test_patch_modal_shows_with_configured_editor, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_context_presets.py:test_gui_context_preset_save_load, tests/test_gui_text_viewer.py:test_text_viewer_state_update, tests/test_patch_modal_gui.py:test_patch_apply_modal_workflow, tests/test_patch_modal_gui.py:test_patch_modal_appears_on_trigger, tests/test_preset_windows_layout.py:test_preset_windows_opening, tests/test_saved_presets_sim.py:test_preset_manager_modal, tests/test_saved_presets_sim.py:test_preset_switching, tests/test_tool_management_layout.py:test_tool_management_state_updates, tests/test_tool_presets_sim.py:test_tool_preset_switching, tests/test_visual_mma.py:test_visual_mma_components, tests/test_visual_sim_gui_ux.py:test_gui_ux_event_routing, tests/test_workspace_profiles_sim.py:test_workspace_profiles_restoration, tests/test_z_negative_flows.py:test_mock_error_result, tests/test_z_negative_flows.py:test_mock_malformed_json, tests/test_z_negative_flows.py:test_mock_timeout]
|
|
"""
|
|
return self.post_gui({"action": action, **payload})
|
|
|
|
def click(self, item: str, user_data: Any = None) -> dict[str, Any]:
|
|
"""
|
|
Simulates a button click.
|
|
[C: simulation/live_walkthrough.py:main, simulation/ping_pong.py:main, simulation/sim_base.py:BaseSimulation.setup, simulation/sim_context.py:ContextSimulation.run, simulation/sim_execution.py:ExecutionSimulation.run, simulation/workflow_sim.py:WorkflowSimulator.create_discussion, simulation/workflow_sim.py:WorkflowSimulator.load_prior_log, simulation/workflow_sim.py:WorkflowSimulator.run_discussion_turn_async, simulation/workflow_sim.py:WorkflowSimulator.setup_new_project, simulation/workflow_sim.py:WorkflowSimulator.truncate_history, simulation/workflow_sim.py:WorkflowSimulator.wait_for_ai_response, tests/test_external_editor_gui.py:test_button_click_is_received, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui2_parity.py:test_gui2_click_hook_works, tests/test_live_workflow.py:test_full_live_workflow, tests/test_mma_concurrent_tracks_sim.py:test_mma_concurrent_tracks_execution, tests/test_mma_concurrent_tracks_stress_sim.py:test_mma_concurrent_tracks_stress, tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow, tests/test_rag_phase4_final_verify.py:test_phase4_final_verify, tests/test_rag_phase4_stress.py:test_rag_large_codebase_verification_sim, tests/test_rag_visual_sim.py:test_rag_full_lifecycle_sim, tests/test_system_prompt_sim.py:test_system_prompt_sim, tests/test_ui_cache_controls_sim.py:test_ui_cache_controls, tests/test_undo_redo_sim.py:test_undo_redo_context_mutation, tests/test_undo_redo_sim.py:test_undo_redo_discussion_mutation, tests/test_undo_redo_sim.py:test_undo_redo_lifecycle, tests/test_visual_orchestration.py:test_mma_epic_lifecycle, tests/test_visual_sim_gui_ux.py:test_gui_track_creation, tests/test_visual_sim_mma_v2.py:_drain_approvals, tests/test_visual_sim_mma_v2.py:test_mma_complete_lifecycle, tests/test_z_negative_flows.py:test_mock_error_result, tests/test_z_negative_flows.py:test_mock_malformed_json, tests/test_z_negative_flows.py:test_mock_timeout]
|
|
"""
|
|
return self.post_gui({"action": "click", "item": item, "user_data": user_data})
|
|
|
|
def set_value(self, item: str, value: Any) -> dict[str, Any]:
|
|
"""
|
|
Sets the value of a GUI widget.
|
|
[C: simulation/live_walkthrough.py:main, simulation/ping_pong.py:main, simulation/sim_ai_settings.py:AISettingsSimulation.run, simulation/sim_base.py:BaseSimulation.setup, simulation/workflow_sim.py:WorkflowSimulator.create_discussion, simulation/workflow_sim.py:WorkflowSimulator.run_discussion_turn_async, simulation/workflow_sim.py:WorkflowSimulator.setup_new_project, simulation/workflow_sim.py:WorkflowSimulator.truncate_history, tests/smoke_status_hook.py:test_status_hook, tests/test_ai_settings_layout.py:test_change_provider_via_hook, tests/test_auto_switch_sim.py:test_auto_switch_sim, tests/test_deepseek_infra.py:test_gui_provider_list_via_hooks, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_gui2_parity.py:test_gui2_click_hook_works, tests/test_gui2_performance.py:test_performance_benchmarking, tests/test_live_gui_integration_v2.py:test_api_gui_state_live, tests/test_live_workflow.py:test_full_live_workflow, tests/test_mma_concurrent_tracks_sim.py:test_mma_concurrent_tracks_execution, tests/test_mma_concurrent_tracks_stress_sim.py:test_mma_concurrent_tracks_stress, tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow, tests/test_rag_phase4_final_verify.py:test_phase4_final_verify, tests/test_rag_phase4_stress.py:test_rag_large_codebase_verification_sim, tests/test_rag_visual_sim.py:test_rag_full_lifecycle_sim, tests/test_rag_visual_sim.py:test_rag_settings_persistence_sim, tests/test_saved_presets_sim.py:test_preset_manager_modal, tests/test_selectable_ui.py:test_selectable_label_stability, tests/test_system_prompt_sim.py:test_system_prompt_sim, tests/test_task_dag_popout_sim.py:test_task_dag_popout, tests/test_tool_presets_sim.py:test_tool_preset_switching, tests/test_undo_redo_sim.py:test_undo_redo_context_mutation, tests/test_undo_redo_sim.py:test_undo_redo_discussion_mutation, tests/test_undo_redo_sim.py:test_undo_redo_lifecycle, tests/test_usage_analytics_popout_sim.py:test_usage_analytics_popout, tests/test_visual_orchestration.py:test_mma_epic_lifecycle, tests/test_visual_sim_gui_ux.py:test_gui_track_creation, tests/test_visual_sim_mma_v2.py:test_mma_complete_lifecycle, tests/test_workspace_profiles_sim.py:test_workspace_profiles_restoration, tests/test_z_negative_flows.py:test_mock_error_result, tests/test_z_negative_flows.py:test_mock_malformed_json, tests/test_z_negative_flows.py:test_mock_timeout]
|
|
"""
|
|
return self.post_gui({"action": "set_value", "item": item, "value": value})
|
|
|
|
def select_tab(self, item: str, value: str) -> dict[str, Any]:
|
|
"""
|
|
Selects a specific tab in a tab bar.
|
|
[C: simulation/live_walkthrough.py:main, tests/test_api_hook_extensions.py:test_select_tab_integration]
|
|
"""
|
|
return self.set_value(item, value)
|
|
|
|
def select_list_item(self, item: str, value: str) -> dict[str, Any]:
|
|
"""
|
|
Selects an item in a listbox or combo.
|
|
[C: simulation/workflow_sim.py:WorkflowSimulator.create_discussion, simulation/workflow_sim.py:WorkflowSimulator.switch_discussion, tests/test_api_hook_extensions.py:test_select_list_item_integration, tests/test_live_workflow.py:test_full_live_workflow]
|
|
"""
|
|
return self.set_value(item, value)
|
|
|
|
def get_gui_state(self) -> dict[str, Any]:
|
|
"""
|
|
Returns the full GUI state available via the hook API.
|
|
[C: tests/test_ai_settings_layout.py:test_change_provider_via_hook, tests/test_ai_settings_layout.py:test_set_params_via_custom_callback, tests/test_conductor_api_hook_integration.py:simulate_conductor_phase_completion, tests/test_external_editor_gui.py:test_button_click_is_received, tests/test_external_editor_gui.py:test_patch_modal_shows_with_configured_editor, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_text_viewer.py:test_text_viewer_state_update, tests/test_hooks.py:test_live_hook_server_responses, tests/test_live_gui_integration_v2.py:test_api_gui_state_live, tests/test_live_workflow.py:test_full_live_workflow, tests/test_live_workflow.py:wait_for_value, tests/test_patch_modal_gui.py:test_patch_apply_modal_workflow, tests/test_patch_modal_gui.py:test_patch_modal_appears_on_trigger, tests/test_rag_phase4_final_verify.py:test_phase4_final_verify, tests/test_rag_phase4_stress.py:test_rag_large_codebase_verification_sim, tests/test_saved_presets_sim.py:test_preset_manager_modal, tests/test_saved_presets_sim.py:test_preset_switching, tests/test_task_dag_popout_sim.py:test_task_dag_popout, tests/test_tool_management_layout.py:test_tool_management_gettable_fields, tests/test_tool_management_layout.py:test_tool_management_state_updates, tests/test_tool_presets_sim.py:test_tool_preset_switching, tests/test_usage_analytics_popout_sim.py:test_usage_analytics_popout]
|
|
"""
|
|
return self._make_request('GET', '/api/gui/state') or {}
|
|
|
|
def get_value(self, item: str) -> Any:
|
|
"""
|
|
Gets the value of a GUI item via its mapped field.
|
|
[C: simulation/sim_ai_settings.py:AISettingsSimulation.run, simulation/sim_base.py:BaseSimulation.get_value, simulation/sim_base.py:BaseSimulation.setup, simulation/sim_base.py:BaseSimulation.wait_for_element, simulation/sim_context.py:ContextSimulation.run, simulation/sim_execution.py:ExecutionSimulation.run, simulation/workflow_sim.py:WorkflowSimulator.run_discussion_turn_async, simulation/workflow_sim.py:WorkflowSimulator.wait_for_ai_response, tests/smoke_status_hook.py:test_status_hook, tests/smoke_status_hook.py:wait_for_value, tests/test_auto_switch_sim.py:test_auto_switch_sim, tests/test_deepseek_infra.py:test_gui_provider_list_via_hooks, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_gui2_parity.py:test_gui2_click_hook_works, tests/test_gui2_parity.py:test_gui2_set_value_hook_works, tests/test_rag_phase4_final_verify.py:test_phase4_final_verify, tests/test_rag_phase4_stress.py:test_rag_large_codebase_verification_sim, tests/test_rag_visual_sim.py:test_rag_full_lifecycle_sim, tests/test_rag_visual_sim.py:test_rag_settings_persistence_sim, tests/test_selectable_ui.py:test_selectable_label_stability, tests/test_system_prompt_sim.py:test_system_prompt_sim, tests/test_undo_redo_sim.py:test_undo_redo_context_mutation, tests/test_undo_redo_sim.py:test_undo_redo_discussion_mutation, tests/test_undo_redo_sim.py:test_undo_redo_lifecycle, tests/test_visual_mma.py:test_visual_mma_components, tests/test_workspace_profiles_sim.py:test_workspace_profiles_restoration]
|
|
"""
|
|
# Try state endpoint first (new preferred way)
|
|
state = self.get_gui_state()
|
|
if item in state:
|
|
return state[item]
|
|
# Fallback for thinking/live/prior which are in diagnostics
|
|
diag = self.get_gui_diagnostics()
|
|
if diag and item in diag:
|
|
return diag[item]
|
|
# Map common indicator tags to diagnostics keys
|
|
mapping = {
|
|
"thinking_indicator": "thinking",
|
|
"operations_live_indicator": "live",
|
|
"prior_session_indicator": "prior"
|
|
}
|
|
key = mapping.get(item)
|
|
if diag and key and key in diag:
|
|
return diag[key]
|
|
return None
|
|
|
|
def get_text_value(self, item_tag: str) -> str | None:
|
|
"""
|
|
Wraps get_value and returns its string representation, or None.
|
|
[C: tests/test_api_hook_client.py:test_get_text_value]
|
|
"""
|
|
val = self.get_value(item_tag)
|
|
return str(val) if val is not None else None
|
|
|
|
def get_indicator_state(self, item_tag: str) -> dict[str, bool]:
|
|
"""
|
|
Returns the visibility/active state of a status indicator.
|
|
[C: simulation/live_walkthrough.py:main, tests/test_api_hook_extensions.py:test_get_indicator_state_integration, tests/test_live_workflow.py:test_full_live_workflow]
|
|
"""
|
|
val = self.get_value(item_tag)
|
|
return {"shown": bool(val)}
|
|
|
|
def get_gui_diagnostics(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves performance and diagnostic metrics.
|
|
[C: tests/test_api_hook_client.py:test_get_performance_success, tests/test_hooks.py:test_live_hook_server_responses, tests/test_selectable_ui.py:test_selectable_label_stability]
|
|
"""
|
|
return self._make_request('GET', '/api/gui/diagnostics') or {}
|
|
|
|
def get_performance(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves performance metrics from the dedicated endpoint.
|
|
[C: tests/test_gui2_performance.py:test_performance_benchmarking, tests/test_gui_performance_requirements.py:test_idle_performance_requirements, tests/test_gui_stress_performance.py:test_comms_volume_stress_performance, tests/test_selectable_ui.py:test_selectable_label_stability, tests/test_visual_sim_gui_ux.py:test_gui_ux_event_routing]
|
|
"""
|
|
return self._make_request('GET', '/api/performance') or {}
|
|
|
|
def get_mma_status(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves the dedicated MMA engine status.
|
|
[C: tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation, tests/test_live_workflow.py:test_full_live_workflow, tests/test_mma_concurrent_tracks_sim.py:_poll_mma_status, tests/test_mma_concurrent_tracks_sim.py:test_mma_concurrent_tracks_execution, tests/test_mma_concurrent_tracks_stress_sim.py:test_mma_concurrent_tracks_stress, tests/test_mma_step_mode_sim.py:_poll_mma_status, tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow, tests/test_visual_orchestration.py:test_mma_epic_lifecycle, tests/test_visual_sim_gui_ux.py:test_gui_ux_event_routing, tests/test_visual_sim_mma_v2.py:_poll]
|
|
"""
|
|
return self._make_request('GET', '/api/gui/mma_status') or {}
|
|
|
|
def get_mma_workers(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves status for all active MMA workers.
|
|
[C: tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation, tests/test_mma_concurrent_tracks_sim.py:test_mma_concurrent_tracks_execution, tests/test_mma_concurrent_tracks_stress_sim.py:_poll_mma_workers]
|
|
"""
|
|
return self._make_request('GET', '/api/mma/workers') or {}
|
|
|
|
def get_context_state(self) -> dict[str, Any]:
|
|
"""
|
|
Retrieves the current file and screenshot context state.
|
|
[C: tests/test_gui_context_presets.py:test_gui_context_preset_save_load]
|
|
"""
|
|
return self._make_request('GET', '/api/context/state') or {}
|
|
|
|
def get_financial_metrics(self) -> dict[str, Any]:
|
|
"""Retrieves token usage and estimated financial cost metrics."""
|
|
return self._make_request('GET', '/api/metrics/financial') or {}
|
|
|
|
def get_system_telemetry(self) -> dict[str, Any]:
|
|
"""Retrieves system-level telemetry including thread status and event queue size."""
|
|
return self._make_request('GET', '/api/system/telemetry') or {}
|
|
|
|
def get_node_status(self, node_id: str) -> dict[str, Any]:
|
|
"""
|
|
Retrieves status for a specific node in the MMA DAG.
|
|
[C: tests/test_api_hook_client.py:test_get_node_status]
|
|
"""
|
|
return self._make_request('GET', f'/api/mma/node/{node_id}') or {}
|
|
|
|
def request_confirmation(self, tool_name: str, args: dict) -> bool | None:
|
|
"""
|
|
|
|
Pushes a manual confirmation request and waits for response.
|
|
Blocks for up to 60 seconds.
|
|
[C: tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation, tests/test_sync_hooks.py:test_api_ask_client_error, tests/test_sync_hooks.py:test_api_ask_client_method, tests/test_sync_hooks.py:test_api_ask_client_rejection]
|
|
"""
|
|
# Long timeout as this waits for human input (60 seconds)
|
|
res = self._make_request('POST', '/api/ask',
|
|
data={'type': 'tool_approval', 'tool': tool_name, 'args': args},
|
|
timeout=60.0)
|
|
return res.get('response') if res else None
|
|
|
|
def reset_session(self) -> None:
|
|
"""
|
|
Resets the current session via button click.
|
|
[C: src/app_controller.py:AppController._handle_reset_session, src/app_controller.py:AppController.current_model, src/app_controller.py:AppController.current_provider, src/app_controller.py:AppController.init_state, src/gui_2.py:App._render_provider_panel, src/gui_2.py:App._show_menus, src/multi_agent_conductor.py:run_worker_lifecycle, tests/conftest.py:live_gui, tests/conftest.py:reset_ai_client, tests/test_ai_cache_tracking.py:test_gemini_cache_tracking, tests/test_ai_client_cli.py:test_ai_client_send_gemini_cli, tests/test_api_events.py:test_send_emits_events_proper, tests/test_api_events.py:test_send_emits_tool_events, tests/test_deepseek_provider.py:test_deepseek_payload_verification, tests/test_deepseek_provider.py:test_deepseek_reasoner_payload_verification, tests/test_gemini_cli_integration.py:test_gemini_cli_full_integration, tests/test_gemini_cli_integration.py:test_gemini_cli_rejection_and_history, tests/test_gemini_metrics.py:test_get_gemini_cache_stats_with_mock_client, tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation, tests/test_minimax_provider.py:test_minimax_history_bleed_stats, tests/test_mma_agent_focus_phase1.py:test_append_comms_has_source_tier_key, tests/test_mma_agent_focus_phase1.py:test_append_comms_source_tier_none_when_unset, tests/test_mma_agent_focus_phase1.py:test_append_comms_source_tier_set_when_current_tier_set, tests/test_mma_agent_focus_phase1.py:test_append_comms_source_tier_tier2, tests/test_session_logger_reset.py:test_reset_session, tests/test_token_usage.py:test_token_usage_tracking]
|
|
"""
|
|
self.click("btn_reset")
|
|
|
|
def trigger_patch(self, patch_text: str, file_paths: list[str]) -> dict[str, Any]:
|
|
"""Triggers the patch modal to show in the GUI."""
|
|
return self._make_request('POST', '/api/patch/trigger', data={
|
|
"patch_text": patch_text,
|
|
"file_paths": file_paths
|
|
}) or {}
|
|
|
|
def apply_patch(self) -> dict[str, Any]:
|
|
"""
|
|
Applies the pending patch.
|
|
[C: tests/test_patch_modal.py:test_apply_callback]
|
|
"""
|
|
return self._make_request('POST', '/api/patch/apply') or {}
|
|
|
|
def reject_patch(self) -> dict[str, Any]:
|
|
"""
|
|
Rejects the pending patch.
|
|
[C: tests/test_patch_modal.py:test_reject_callback, tests/test_patch_modal.py:test_reject_patch]
|
|
"""
|
|
return self._make_request('POST', '/api/patch/reject') or {}
|
|
|
|
def get_patch_status(self) -> dict[str, Any]:
|
|
"""Gets the current patch modal status."""
|
|
return self._make_request('GET', '/api/patch/status') or {}
|
|
|
|
def spawn_mma_worker(self, data: dict) -> dict:
|
|
"""
|
|
Spawns a new MMA worker with the provided configuration.
|
|
[C: tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation]
|
|
"""
|
|
return self._make_request('POST', '/api/mma/workers/spawn', data=data) or {}
|
|
|
|
def kill_mma_worker(self, worker_id: str) -> dict:
|
|
"""Kills an active MMA worker by its ID."""
|
|
return self._make_request('POST', '/api/mma/workers/kill', data={"worker_id": worker_id}) or {}
|
|
|
|
def pause_mma_pipeline(self) -> dict:
|
|
"""
|
|
Pauses the MMA execution pipeline.
|
|
[C: tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow]
|
|
"""
|
|
return self._make_request('POST', '/api/mma/pipeline/pause') or {}
|
|
|
|
def resume_mma_pipeline(self) -> dict:
|
|
"""Resumes the MMA execution pipeline."""
|
|
return self._make_request('POST', '/api/mma/pipeline/resume') or {}
|
|
|
|
def inject_context(self, data: dict) -> dict:
|
|
"""
|
|
Injects custom file context into the application.
|
|
[C: tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation]
|
|
"""
|
|
return self._make_request('POST', '/api/context/inject', data=data) or {}
|
|
|
|
def mutate_mma_dag(self, data: dict) -> dict:
|
|
"""
|
|
Mutates the MMA DAG (Directed Acyclic Graph) structure.
|
|
[C: tests/test_headless_simulation.py:test_mma_track_lifecycle_simulation]
|
|
"""
|
|
return self._make_request('POST', '/api/mma/dag/mutate', data=data) or {}
|
|
|
|
def approve_mma_ticket(self, ticket_id: str) -> dict:
|
|
"""
|
|
Manually approves a specific ticket for execution in Step Mode.
|
|
[C: tests/test_mma_step_mode_sim.py:test_mma_step_mode_approval_flow]
|
|
"""
|
|
return self._make_request('POST', '/api/mma/ticket/approve', data={"ticket_id": ticket_id}) or {}
|