refactor(project_manager,aggregate,api_hook_client): replace weak type sites with aliases

This commit is contained in:
ed
2026-06-21 12:39:17 -04:00
parent d0c0571bde
commit 833e99f2ec
3 changed files with 100 additions and 62 deletions
+20 -8
View File
@@ -33,6 +33,18 @@ from src.fuzzy_anchor import FuzzyAnchor
from src.file_cache import ASTParser from src.file_cache import ASTParser
from src.paths import get_config_path from src.paths import get_config_path
from src.performance_monitor import get_monitor from src.performance_monitor import get_monitor
from src.type_aliases import (
CommsLog,
CommsLogCallback,
CommsLogEntry,
FileItem,
FileItems,
History,
HistoryMessage,
Metadata,
ToolCall,
ToolDefinition,
)
def find_next_increment(output_dir: Path, namespace: str) -> int: def find_next_increment(output_dir: Path, namespace: str) -> int:
@@ -143,7 +155,7 @@ def build_screenshots_section(base_dir: Path, screenshots: list[str]) -> str:
sections.append(f"### `{original}`\n\n![{path.name}]({path.as_posix()})") sections.append(f"### `{original}`\n\n![{path.name}]({path.as_posix()})")
return "\n\n---\n\n".join(sections) return "\n\n---\n\n".join(sections)
def build_file_items(base_dir: Path, files: list[str | dict[str, Any]]) -> list[dict[str, Any]]: def build_file_items(base_dir: Path, files: list[str | Metadata]) -> list[Metadata]:
""" """
Return a list of dicts describing each file, for use by ai_client when it Return a list of dicts describing each file, for use by ai_client when it
wants to upload individual files rather than inline everything as markdown. wants to upload individual files rather than inline everything as markdown.
@@ -161,7 +173,7 @@ def build_file_items(base_dir: Path, files: list[str | dict[str, Any]]) -> list[
[C: src/app_controller.py:AppController._bg_task, src/orchestrator_pm.py:module, tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_aggregate_flags.py:test_force_full, tests/test_context_composition_phase6.py:test_view_mode_custom, tests/test_context_composition_phase6.py:test_view_mode_custom_empty_default_to_summary, tests/test_context_composition_phase6.py:test_view_mode_default_summary, tests/test_context_composition_phase6.py:test_view_mode_full, tests/test_context_composition_phase6.py:test_view_mode_none, tests/test_context_composition_phase6.py:test_view_mode_outline, tests/test_context_composition_phase6.py:test_view_mode_skeleton, tests/test_context_composition_phase6.py:test_view_mode_summary, tests/test_tiered_context.py:test_build_file_items_with_tiers, tests/test_tiered_context.py:test_build_files_section_with_dicts] [C: src/app_controller.py:AppController._bg_task, src/orchestrator_pm.py:module, tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_aggregate_flags.py:test_force_full, tests/test_context_composition_phase6.py:test_view_mode_custom, tests/test_context_composition_phase6.py:test_view_mode_custom_empty_default_to_summary, tests/test_context_composition_phase6.py:test_view_mode_default_summary, tests/test_context_composition_phase6.py:test_view_mode_full, tests/test_context_composition_phase6.py:test_view_mode_none, tests/test_context_composition_phase6.py:test_view_mode_outline, tests/test_context_composition_phase6.py:test_view_mode_skeleton, tests/test_context_composition_phase6.py:test_view_mode_summary, tests/test_tiered_context.py:test_build_file_items_with_tiers, tests/test_tiered_context.py:test_build_files_section_with_dicts]
""" """
with get_monitor().scope("build_file_items"): with get_monitor().scope("build_file_items"):
items: list[dict[str, Any]] = [] items: list[Metadata] = []
parser = None parser = None
for entry_raw in files: for entry_raw in files:
if isinstance(entry_raw, dict): if isinstance(entry_raw, dict):
@@ -285,7 +297,7 @@ def build_file_items(base_dir: Path, files: list[str | dict[str, Any]]) -> list[
items.append({"path": path, "entry": entry, "content": content, "error": error, "mtime": mtime, "tier": tier, "auto_aggregate": auto_aggregate, "force_full": force_full, "view_mode": view_mode, "ast_signatures": ast_signatures, "ast_definitions": ast_definitions, "ast_mask": ast_mask, "custom_slices": custom_slices}) items.append({"path": path, "entry": entry, "content": content, "error": error, "mtime": mtime, "tier": tier, "auto_aggregate": auto_aggregate, "force_full": force_full, "view_mode": view_mode, "ast_signatures": ast_signatures, "ast_definitions": ast_definitions, "ast_mask": ast_mask, "custom_slices": custom_slices})
return items return items
def _build_files_section_from_items(file_items: list[dict[str, Any]]) -> str: def _build_files_section_from_items(file_items: list[Metadata]) -> str:
""" """
Build the files markdown section from pre-read file items (avoids double I/O). Build the files markdown section from pre-read file items (avoids double I/O).
[C: tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_context_composition_phase6.py:test_files_section_rendering, tests/test_tiered_context.py:test_build_files_section_with_dicts, tests/test_ui_summary_only_removal.py:test_aggregate_from_items_respects_auto_aggregate] [C: tests/test_aggregate_flags.py:test_auto_aggregate_skip, tests/test_context_composition_phase6.py:test_files_section_rendering, tests/test_tiered_context.py:test_build_files_section_with_dicts, tests/test_ui_summary_only_removal.py:test_aggregate_from_items_respects_auto_aggregate]
@@ -333,7 +345,7 @@ def build_beads_section(base_dir: Path) -> str:
for b in active: parts.append(f"- **{b.title}** ({b.id}): {b.description}") for b in active: parts.append(f"- **{b.title}** ({b.id}): {b.description}")
return "\n\n".join(parts) return "\n\n".join(parts)
def build_markdown_from_items(file_items: list[dict[str, Any]], screenshot_base_dir: Path, screenshots: list[str], history: list[str], summary_only: bool = False, aggregation_strategy: str = "auto", execution_mode: str = "standard", base_dir: Path | None = None) -> str: def build_markdown_from_items(file_items: list[Metadata], screenshot_base_dir: Path, screenshots: list[str], history: list[str], summary_only: bool = False, aggregation_strategy: str = "auto", execution_mode: str = "standard", base_dir: Path | None = None) -> str:
"""Build markdown from pre-read file items instead of re-reading from disk.""" """Build markdown from pre-read file items instead of re-reading from disk."""
parts = [] parts = []
# STATIC PREFIX: Files and Screenshots must go first to maximize Cache Hits # STATIC PREFIX: Files and Screenshots must go first to maximize Cache Hits
@@ -351,7 +363,7 @@ def build_markdown_from_items(file_items: list[dict[str, Any]], screenshot_base_
if history: parts.append("## Discussion History\n\n" + build_discussion_section(history)) if history: parts.append("## Discussion History\n\n" + build_discussion_section(history))
return "\n\n---\n\n".join(parts) return "\n\n---\n\n".join(parts)
def build_markdown_no_history(file_items: list[dict[str, Any]], screenshot_base_dir: Path, screenshots: list[str], summary_only: bool = False, aggregation_strategy: str = "auto") -> str: def build_markdown_no_history(file_items: list[Metadata], screenshot_base_dir: Path, screenshots: list[str], summary_only: bool = False, aggregation_strategy: str = "auto") -> str:
""" """
Build markdown with only files + screenshots (no history). Used for stable caching. Build markdown with only files + screenshots (no history). Used for stable caching.
[C: src/app_controller.py:AppController._do_generate, tests/test_history_management.py:test_aggregate_blacklist] [C: src/app_controller.py:AppController._do_generate, tests/test_history_management.py:test_aggregate_blacklist]
@@ -367,7 +379,7 @@ def build_discussion_text(history: list[str]) -> str:
return "" return ""
return "## Discussion History\n\n" + build_discussion_section(history) return "## Discussion History\n\n" + build_discussion_section(history)
def build_tier3_context(file_items: list[dict[str, Any]], screenshot_base_dir: Path, screenshots: list[str], history: list[str], focus_files: list[str]) -> str: def build_tier3_context(file_items: list[Metadata], screenshot_base_dir: Path, screenshots: list[str], history: list[str], focus_files: list[str]) -> str:
""" """
Tier 3 Context: Execution/Worker. Tier 3 Context: Execution/Worker.
Full content for focus_files and files with tier=3, summaries/skeletons for others. Full content for focus_files and files with tier=3, summaries/skeletons for others.
@@ -460,11 +472,11 @@ def build_tier3_context(file_items: list[dict[str, Any]], screenshot_base_dir: P
if history: parts.append("## Discussion History\n\n" + build_discussion_section(history)) if history: parts.append("## Discussion History\n\n" + build_discussion_section(history))
return "\n\n---\n\n".join(parts) return "\n\n---\n\n".join(parts)
def build_markdown(base_dir: Path, files: list[str | dict[str, Any]], screenshot_base_dir: Path, screenshots: list[str], history: list[str], summary_only: bool = False, execution_mode: str = "standard") -> str: def build_markdown(base_dir: Path, files: list[str | Metadata], screenshot_base_dir: Path, screenshots: list[str], history: list[str], summary_only: bool = False, execution_mode: str = "standard") -> str:
file_items = build_file_items(base_dir, files) file_items = build_file_items(base_dir, files)
return build_markdown_from_items(file_items, screenshot_base_dir, screenshots, history, summary_only=summary_only, aggregation_strategy='auto', execution_mode=execution_mode, base_dir=base_dir) return build_markdown_from_items(file_items, screenshot_base_dir, screenshots, history, summary_only=summary_only, aggregation_strategy='auto', execution_mode=execution_mode, base_dir=base_dir)
def run(config: dict[str, Any], aggregation_strategy: str = "auto") -> tuple[str, Path, list[dict[str, Any]]]: def run(config: Metadata, aggregation_strategy: str = "auto") -> tuple[str, Path, list[Metadata]]:
""" """
[C: simulation/sim_base.py:run_sim, src/ai_client.py:_send_anthropic, src/ai_client.py:_send_deepseek, src/ai_client.py:_send_gemini, src/ai_client.py:_send_gemini_cli, src/ai_client.py:_send_minimax, src/app_controller.py:AppController._cb_start_track, src/app_controller.py:AppController._do_generate, src/app_controller.py:AppController._process_event_queue, src/app_controller.py:AppController._start_track_logic, src/external_editor.py:_find_vscode_in_registry, src/gui_2.py:App._render_snapshot_tab, src/gui_2.py:App.run, src/gui_2.py:main, src/mcp_client.py:get_git_diff, src/project_manager.py:get_git_commit, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, 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:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run] [C: simulation/sim_base.py:run_sim, src/ai_client.py:_send_anthropic, src/ai_client.py:_send_deepseek, src/ai_client.py:_send_gemini, src/ai_client.py:_send_gemini_cli, src/ai_client.py:_send_minimax, src/app_controller.py:AppController._cb_start_track, src/app_controller.py:AppController._do_generate, src/app_controller.py:AppController._process_event_queue, src/app_controller.py:AppController._start_track_logic, src/external_editor.py:_find_vscode_in_registry, src/gui_2.py:App._render_snapshot_tab, src/gui_2.py:App.run, src/gui_2.py:main, src/mcp_client.py:get_git_diff, src/project_manager.py:get_git_commit, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, 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:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run]
""" """
+53 -40
View File
@@ -9,7 +9,7 @@ This module provides a Python client for interacting with the Hook API exposed b
Architecture: Architecture:
- Uses requests library for HTTP communication - Uses requests library for HTTP communication
- All methods return dict[str, Any] or None - All methods return Metadata or None
- Handles connection errors gracefully (returns None on failure) - Handles connection errors gracefully (returns None on failure)
Key Method Categories: Key Method Categories:
@@ -37,6 +37,19 @@ import requests # type: ignore[import-untyped]
import sys import sys
import time import time
from src.type_aliases import (
CommsLog,
CommsLogCallback,
CommsLogEntry,
FileItem,
FileItems,
History,
HistoryMessage,
Metadata,
ToolCall,
ToolDefinition,
)
from typing import Any from typing import Any
@@ -49,7 +62,7 @@ class ApiHookClient:
self.base_url = base_url.rstrip('/') self.base_url = base_url.rstrip('/')
self.api_key = api_key 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: def _make_request(self, method: str, path: str, data: dict | None = None, timeout: float = 5.0) -> Metadata | None:
""" """
Helper to make HTTP requests to the hook server. Helper to make HTTP requests to the hook server.
[C: tests/test_api_hook_client.py:test_unsupported_method_error] [C: tests/test_api_hook_client.py:test_unsupported_method_error]
@@ -89,7 +102,7 @@ class ApiHookClient:
time.sleep(0.5) time.sleep(0.5)
return False return False
def get_status(self) -> dict[str, Any]: def get_status(self) -> Metadata:
""" """
Checks the health of the hook server. 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_phase6_simulation.py:test_ast_inspector_modal_opens, tests/test_phase6_simulation.py:test_batch_operations_shift_click, tests/test_phase6_simulation.py:test_slice_editor_add_remove, 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] [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_phase6_simulation.py:test_ast_inspector_modal_opens, tests/test_phase6_simulation.py:test_batch_operations_shift_click, tests/test_phase6_simulation.py:test_slice_editor_add_remove, 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]
@@ -101,26 +114,26 @@ class ApiHookClient:
return {} return {}
return res return res
def post_session(self, session_entries: list[dict]) -> dict[str, Any]: def post_session(self, session_entries: list[dict]) -> Metadata:
""" """
Updates the session history. 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] [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 {} return self._make_request('POST', '/api/session', data={"session": {"entries": session_entries}}) or {}
def get_events(self) -> list[dict[str, Any]]: def get_events(self) -> list[Metadata]:
"""Retrieves any pending events from the API event queue.""" """Retrieves any pending events from the API event queue."""
res = self._make_request('GET', '/api/events') res = self._make_request('GET', '/api/events')
return res.get("events", []) if res else [] return res.get("events", []) if res else []
def clear_events(self) -> list[dict[str, Any]]: def clear_events(self) -> list[Metadata]:
""" """
Retrieves and clears the event queue. Retrieves and clears the event queue.
[C: simulation/sim_base.py:BaseSimulation.setup] [C: simulation/sim_base.py:BaseSimulation.setup]
""" """
return self.get_events() return self.get_events()
def wait_for_event(self, event_type: str, timeout: int = 5) -> dict[str, Any] | None: def wait_for_event(self, event_type: str, timeout: int = 5) -> Metadata | 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] [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]
""" """
@@ -133,14 +146,14 @@ class ApiHookClient:
time.sleep(0.2) time.sleep(0.2)
return None return None
def post_gui(self, payload: dict) -> dict[str, Any]: def post_gui(self, payload: dict) -> Metadata:
""" """
Pushes an event to the GUI's AsyncEventQueue via the /api/gui endpoint. 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] [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]
""" """
return self._make_request('POST', '/api/gui', data=payload) or {} return self._make_request('POST', '/api/gui', data=payload) or {}
def push_event(self, action: str, payload: dict) -> dict[str, Any]: def push_event(self, action: str, payload: dict) -> Metadata:
""" """
Convenience to push a GUI task. 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_track_creation, 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] [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_track_creation, 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]
@@ -149,7 +162,7 @@ class ApiHookClient:
#region: Data #region: Data
def get_gui_state(self) -> dict[str, Any]: def get_gui_state(self) -> Metadata:
""" """
Returns the full GUI state available via the hook API. 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, tests/test_visual_mma.py:test_visual_mma_components] [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, tests/test_visual_mma.py:test_visual_mma_components]
@@ -196,7 +209,7 @@ class ApiHookClient:
val = self.get_value(item_tag) val = self.get_value(item_tag)
return str(val) if val is not None else None return str(val) if val is not None else None
def set_value(self, item: str, value: Any) -> dict[str, Any]: def set_value(self, item: str, value: Any) -> Metadata:
""" """
Sets the value of a GUI widget. 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_mma.py:test_visual_mma_components, tests/test_visual_orchestration.py:test_mma_epic_lifecycle, 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] [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_mma.py:test_visual_mma_components, tests/test_visual_orchestration.py:test_mma_epic_lifecycle, 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]
@@ -207,21 +220,21 @@ class ApiHookClient:
#region: Input #region: Input
def click(self, item: str, user_data: Any = None) -> dict[str, Any]: def click(self, item: str, user_data: Any = None) -> Metadata:
""" """
Simulates a button click. 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_gui_text_viewer.py:test_text_viewer_state_update, 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_saved_presets_sim.py:test_preset_manager_modal, tests/test_saved_presets_sim.py:test_preset_switching, 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_mma.py:test_visual_mma_components, 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:_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] [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_gui_text_viewer.py:test_text_viewer_state_update, 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_saved_presets_sim.py:test_preset_manager_modal, tests/test_saved_presets_sim.py:test_preset_switching, 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_mma.py:test_visual_mma_components, 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:_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}) return self.post_gui({"action": "click", "item": item, "user_data": user_data})
def drag(self, src_item: str, dst_item: str) -> dict[str, Any]: def drag(self, src_item: str, dst_item: str) -> Metadata:
""" """
Simulates a drag and drop operation. Simulates a drag and drop operation.
[C: tests/test_api_hook_client.py:test_drag_success] [C: tests/test_api_hook_client.py:test_drag_success]
""" """
return self.push_event("drag", {"src_item": src_item, "dst_item": dst_item}) return self.push_event("drag", {"src_item": src_item, "dst_item": dst_item})
def right_click(self, item: str) -> dict[str, Any]: def right_click(self, item: str) -> Metadata:
""" """
Simulates a right-click on an item. Simulates a right-click on an item.
[C: tests/test_api_hook_client.py:test_right_click_success] [C: tests/test_api_hook_client.py:test_right_click_success]
@@ -240,14 +253,14 @@ class ApiHookClient:
timeout=60.0) timeout=60.0)
return res.get('response') if res else None return res.get('response') if res else None
def select_list_item(self, item: str, value: str) -> dict[str, Any]: def select_list_item(self, item: str, value: str) -> Metadata:
""" """
Selects an item in a listbox or combo. 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] [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) return self.set_value(item, value)
def select_tab(self, item: str, value: str) -> dict[str, Any]: def select_tab(self, item: str, value: str) -> Metadata:
""" """
Selects a specific tab in a tab bar. Selects a specific tab in a tab bar.
[C: simulation/live_walkthrough.py:main, tests/test_api_hook_extensions.py:test_select_tab_integration] [C: simulation/live_walkthrough.py:main, tests/test_api_hook_extensions.py:test_select_tab_integration]
@@ -258,28 +271,28 @@ class ApiHookClient:
#region: Patching #region: Patching
def trigger_patch(self, patch_text: str, file_paths: list[str]) -> dict[str, Any]: def trigger_patch(self, patch_text: str, file_paths: list[str]) -> Metadata:
"""Triggers the patch modal to show in the GUI.""" """Triggers the patch modal to show in the GUI."""
return self._make_request('POST', '/api/patch/trigger', data={ return self._make_request('POST', '/api/patch/trigger', data={
"patch_text": patch_text, "patch_text": patch_text,
"file_paths": file_paths "file_paths": file_paths
}) or {} }) or {}
def apply_patch(self) -> dict[str, Any]: def apply_patch(self) -> Metadata:
""" """
Applies the pending patch. Applies the pending patch.
[C: tests/test_patch_modal.py:test_apply_callback] [C: tests/test_patch_modal.py:test_apply_callback]
""" """
return self._make_request('POST', '/api/patch/apply') or {} return self._make_request('POST', '/api/patch/apply') or {}
def reject_patch(self) -> dict[str, Any]: def reject_patch(self) -> Metadata:
""" """
Rejects the pending patch. Rejects the pending patch.
[C: tests/test_patch_modal.py:test_reject_callback, tests/test_patch_modal.py:test_reject_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 {} return self._make_request('POST', '/api/patch/reject') or {}
def get_patch_status(self) -> dict[str, Any]: def get_patch_status(self) -> Metadata:
"""Gets the current patch modal status.""" """Gets the current patch modal status."""
return self._make_request('GET', '/api/patch/status') or {} return self._make_request('GET', '/api/patch/status') or {}
@@ -295,28 +308,28 @@ class ApiHookClient:
val = self.get_value(item_tag) val = self.get_value(item_tag)
return {"shown": bool(val)} return {"shown": bool(val)}
def get_gui_diagnostics(self) -> dict[str, Any]: def get_gui_diagnostics(self) -> Metadata:
""" """
Retrieves performance and diagnostic metrics. 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, tests/test_visual_sim_gui_ux.py:test_gui_ux_event_routing] [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, tests/test_visual_sim_gui_ux.py:test_gui_ux_event_routing]
""" """
return self._make_request('GET', '/api/gui/diagnostics') or {} return self._make_request('GET', '/api/gui/diagnostics') or {}
def get_performance(self) -> dict[str, Any]: def get_performance(self) -> Metadata:
""" """
Retrieves performance metrics from the dedicated endpoint. 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] [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]
""" """
return self._make_request('GET', '/api/performance') or {} return self._make_request('GET', '/api/performance') or {}
def get_warmup_status(self) -> dict[str, Any]: def get_warmup_status(self) -> Metadata:
""" """
Returns the current warmup status: {pending, completed, failed}. Returns the current warmup status: {pending, completed, failed}.
[C: tests/test_api_hooks_warmup.py:test_get_warmup_status_calls_correct_endpoint, tests/test_api_hooks_warmup.py:test_get_warmup_status_handles_empty_response, tests/test_api_hooks_warmup.py:test_live_warmup_status_endpoint] [C: tests/test_api_hooks_warmup.py:test_get_warmup_status_calls_correct_endpoint, tests/test_api_hooks_warmup.py:test_get_warmup_status_handles_empty_response, tests/test_api_hooks_warmup.py:test_live_warmup_status_endpoint]
""" """
return self._make_request('GET', '/api/warmup_status') or {} return self._make_request('GET', '/api/warmup_status') or {}
def get_warmup_wait(self, timeout: float = 30.0) -> dict[str, Any]: def get_warmup_wait(self, timeout: float = 30.0) -> Metadata:
""" """
Blocks server-side up to `timeout` seconds waiting for the warmup to Blocks server-side up to `timeout` seconds waiting for the warmup to
complete, then returns the final status. Useful for external clients complete, then returns the final status. Useful for external clients
@@ -326,7 +339,7 @@ class ApiHookClient:
""" """
return self._make_request('GET', f'/api/warmup_wait?timeout={timeout}') or {} return self._make_request('GET', f'/api/warmup_wait?timeout={timeout}') or {}
def get_warmup_canaries(self) -> list[dict[str, Any]]: def get_warmup_canaries(self) -> list[Metadata]:
""" """
Returns per-module import canary records: list of dicts with Returns per-module import canary records: list of dicts with
canary_id, module, thread_name, thread_id, submit_ts, start_ts, canary_id, module, thread_name, thread_id, submit_ts, start_ts,
@@ -337,7 +350,7 @@ class ApiHookClient:
result = self._make_request('GET', '/api/warmup_canaries') or {} result = self._make_request('GET', '/api/warmup_canaries') or {}
return result.get("canaries", []) if isinstance(result, dict) else [] return result.get("canaries", []) if isinstance(result, dict) else []
def get_startup_timeline(self) -> dict[str, Any]: def get_startup_timeline(self) -> Metadata:
""" """
Returns the startup timeline: dict with init_start_ts, warmup_done_ts, Returns the startup timeline: dict with init_start_ts, warmup_done_ts,
first_frame_ts, warmup_ms, first_frame_after_init_ms, first_frame_ts, warmup_ms, first_frame_after_init_ms,
@@ -351,14 +364,14 @@ class ApiHookClient:
#region: Project #region: Project
def get_project(self) -> dict[str, Any]: def get_project(self) -> Metadata:
""" """
Retrieves the current project state. 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] [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 {} return self._make_request('GET', '/api/project') or {}
def get_project_switch_status(self) -> dict[str, Any]: def get_project_switch_status(self) -> Metadata:
""" """
Returns the project switch status: {in_progress, path, error}. Returns the project switch status: {in_progress, path, error}.
- in_progress: True when a project switch is currently scheduled or running - in_progress: True when a project switch is currently scheduled or running
@@ -373,7 +386,7 @@ class ApiHookClient:
return {"in_progress": False, "path": None, "error": None} return {"in_progress": False, "path": None, "error": None}
return result return result
def wait_for_project_switch(self, expected_path: str = None, timeout: float = 30.0, poll_interval: float = 0.2) -> dict[str, Any]: def wait_for_project_switch(self, expected_path: str = None, timeout: float = 30.0, poll_interval: float = 0.2) -> Metadata:
""" """
Blocks until the project switch completes (or fails). Returns the Blocks until the project switch completes (or fails). Returns the
final status dict. If expected_path is provided, also waits until the final status dict. If expected_path is provided, also waits until the
@@ -404,7 +417,7 @@ class ApiHookClient:
last_status["timeout"] = True last_status["timeout"] = True
return last_status return last_status
def get_io_pool_status(self) -> dict[str, Any]: def get_io_pool_status(self) -> Metadata:
""" """
Returns the controller's io_pool status: {idle, inflight}. Returns the controller's io_pool status: {idle, inflight}.
- idle: True if no jobs are currently in-flight (running or queued) - idle: True if no jobs are currently in-flight (running or queued)
@@ -418,7 +431,7 @@ class ApiHookClient:
return {"idle": True, "inflight": 0} return {"idle": True, "inflight": 0}
return result return result
def get_gui_health(self) -> dict[str, Any]: def get_gui_health(self) -> Metadata:
""" """
Returns the controller's GUI health: {healthy, degraded_reason, Returns the controller's GUI health: {healthy, degraded_reason,
last_assert, io_pool_alive}. Tests should call this before starting last_assert, io_pool_alive}. Tests should call this before starting
@@ -454,10 +467,10 @@ class ApiHookClient:
time.sleep(poll_interval) time.sleep(poll_interval)
return False return False
def post_project(self, project_data: dict) -> dict[str, Any]: def post_project(self, project_data: dict) -> Metadata:
return last_status return last_status
def post_project(self, project_data: dict) -> dict[str, Any]: def post_project(self, project_data: dict) -> Metadata:
""" """
Updates the current project configuration. Updates the current project configuration.
[C: simulation/sim_context.py:ContextSimulation.run] [C: simulation/sim_context.py:ContextSimulation.run]
@@ -475,7 +488,7 @@ class ApiHookClient:
""" """
return self._make_request('POST', '/api/context/inject', data=data) or {} return self._make_request('POST', '/api/context/inject', data=data) or {}
def get_context_state(self) -> dict[str, Any]: def get_context_state(self) -> Metadata:
""" """
Retrieves the current file and screenshot context state. Retrieves the current file and screenshot context state.
[C: tests/test_gui_context_presets.py:test_gui_context_preset_save_load] [C: tests/test_gui_context_presets.py:test_gui_context_preset_save_load]
@@ -486,7 +499,7 @@ class ApiHookClient:
#region: Discussion #region: Discussion
def get_session(self) -> dict[str, Any]: def get_session(self) -> Metadata:
""" """
Retrieves the current discussion session history. 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] [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]
@@ -504,11 +517,11 @@ class ApiHookClient:
#region: Analytics #region: Analytics
def get_financial_metrics(self) -> dict[str, Any]: def get_financial_metrics(self) -> Metadata:
"""Retrieves token usage and estimated financial cost metrics.""" """Retrieves token usage and estimated financial cost metrics."""
return self._make_request('GET', '/api/metrics/financial') or {} return self._make_request('GET', '/api/metrics/financial') or {}
def get_system_telemetry(self) -> dict[str, Any]: def get_system_telemetry(self) -> Metadata:
"""Retrieves system-level telemetry including thread status and event queue size.""" """Retrieves system-level telemetry including thread status and event queue size."""
return self._make_request('GET', '/api/system/telemetry') or {} return self._make_request('GET', '/api/system/telemetry') or {}
@@ -516,21 +529,21 @@ class ApiHookClient:
#region: MMA #region: MMA
def get_node_status(self, node_id: str) -> dict[str, Any]: def get_node_status(self, node_id: str) -> Metadata:
""" """
Retrieves status for a specific node in the MMA DAG. Retrieves status for a specific node in the MMA DAG.
[C: tests/test_api_hook_client.py:test_get_node_status] [C: tests/test_api_hook_client.py:test_get_node_status]
""" """
return self._make_request('GET', f'/api/mma/node/{node_id}') or {} return self._make_request('GET', f'/api/mma/node/{node_id}') or {}
def get_mma_status(self) -> dict[str, Any]: def get_mma_status(self) -> Metadata:
""" """
Retrieves the dedicated MMA engine status. 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_mma.py:test_visual_mma_components, 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] [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_mma.py:test_visual_mma_components, 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 {} return self._make_request('GET', '/api/gui/mma_status') or {}
def get_mma_workers(self) -> dict[str, Any]: def get_mma_workers(self) -> Metadata:
""" """
Retrieves status for all active MMA workers. 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] [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]
+27 -14
View File
@@ -17,6 +17,19 @@ from typing import Any, Optional, TYPE_CHECKING, Union
from src import paths from src import paths
from src.type_aliases import (
CommsLog,
CommsLogCallback,
CommsLogEntry,
FileItem,
FileItems,
History,
HistoryMessage,
Metadata,
ToolCall,
ToolDefinition,
)
if TYPE_CHECKING: if TYPE_CHECKING:
from src.models import TrackState from src.models import TrackState
@@ -33,7 +46,7 @@ def parse_ts(s: str) -> Optional[datetime.datetime]:
return None return None
# ── entry serialisation ────────────────────────────────────────────────────── # ── entry serialisation ──────────────────────────────────────────────────────
def entry_to_str(entry: dict[str, Any]) -> str: def entry_to_str(entry: Metadata) -> str:
""" """
Serialise a disc entry dict -> stored string. Serialise a disc entry dict -> stored string.
[C: tests/test_thinking_persistence.py:test_entry_to_str_with_thinking] [C: tests/test_thinking_persistence.py:test_entry_to_str_with_thinking]
@@ -53,13 +66,13 @@ def entry_to_str(entry: dict[str, Any]) -> str:
return f"@{ts}\n{role}:\n{content}" return f"@{ts}\n{role}:\n{content}"
return f"{role}:\n{content}" return f"{role}:\n{content}"
def format_discussion(entries: list[dict[str, Any]]) -> str: def format_discussion(entries: list[Metadata]) -> str:
""" """
Convert a list of discussion entry dicts into a single formatted string. Convert a list of discussion entry dicts into a single formatted string.
""" """
return "\n\n".join([entry_to_str(e) for e in entries]) return "\n\n".join([entry_to_str(e) for e in entries])
def str_to_entry(raw: str, roles: list[str]) -> dict[str, Any]: def str_to_entry(raw: str, roles: list[str]) -> Metadata:
""" """
Parse a stored string back to a disc entry dict. Parse a stored string back to a disc entry dict.
[C: tests/test_thinking_persistence.py:test_str_to_entry_with_thinking] [C: tests/test_thinking_persistence.py:test_str_to_entry_with_thinking]
@@ -101,13 +114,13 @@ def get_git_commit(git_dir: str) -> str:
# ── default structures ─────────────────────────────────────────────────────── # ── default structures ───────────────────────────────────────────────────────
def default_discussion() -> dict[str, Any]: def default_discussion() -> Metadata:
""" """
[C: tests/test_discussion_takes.py:TestDiscussionTakes.test_promote_take_renames_discussion] [C: tests/test_discussion_takes.py:TestDiscussionTakes.test_promote_take_renames_discussion]
""" """
return {"git_commit": "", "last_updated": now_ts(), "history": []} return {"git_commit": "", "last_updated": now_ts(), "history": []}
def default_project(name: str = "unnamed") -> dict[str, Any]: def default_project(name: str = "unnamed") -> Metadata:
""" """
[C: tests/test_deepseek_infra.py:test_default_project_includes_reasoning_role, tests/test_discussion_takes.py:TestDiscussionTakes.setUp, tests/test_history_management.py:test_history_persistence_across_turns, tests/test_history_management.py:test_save_separation, tests/test_project_manager_modes.py:test_default_project_execution_mode, tests/test_project_manager_modes.py:test_load_save_execution_mode, tests/test_project_serialization.py:TestProjectSerialization.test_default_roles_include_context, tests/test_project_serialization.py:TestProjectSerialization.test_fileitem_roundtrip] [C: tests/test_deepseek_infra.py:test_default_project_includes_reasoning_role, tests/test_discussion_takes.py:TestDiscussionTakes.setUp, tests/test_history_management.py:test_history_persistence_across_turns, tests/test_history_management.py:test_save_separation, tests/test_project_manager_modes.py:test_default_project_execution_mode, tests/test_project_manager_modes.py:test_load_save_execution_mode, tests/test_project_serialization.py:TestProjectSerialization.test_default_roles_include_context, tests/test_project_serialization.py:TestProjectSerialization.test_fileitem_roundtrip]
""" """
@@ -170,7 +183,7 @@ def get_history_path(project_path: Union[str, Path]) -> Path:
p = Path(project_path) p = Path(project_path)
return p.parent / f"{p.stem}_history.toml" return p.parent / f"{p.stem}_history.toml"
def load_project(path: Union[str, Path]) -> dict[str, Any]: def load_project(path: Union[str, Path]) -> Metadata:
""" """
Load a project TOML file. Load a project TOML file.
Automatically migrates legacy 'discussion' keys to a sibling history file. Automatically migrates legacy 'discussion' keys to a sibling history file.
@@ -193,7 +206,7 @@ def load_project(path: Union[str, Path]) -> dict[str, Any]:
proj["discussion"] = load_history(path) proj["discussion"] = load_history(path)
return proj return proj
def load_history(project_path: Union[str, Path]) -> dict[str, Any]: def load_history(project_path: Union[str, Path]) -> Metadata:
""" """
Load the segregated discussion history from its dedicated TOML file. Load the segregated discussion history from its dedicated TOML file.
[C: tests/test_thinking_persistence.py:test_save_and_load_history_with_thinking_segments] [C: tests/test_thinking_persistence.py:test_save_and_load_history_with_thinking_segments]
@@ -213,7 +226,7 @@ def clean_nones(data: Any) -> Any:
elif isinstance(data, list): return [clean_nones(v) for v in data if v is not None] elif isinstance(data, list): return [clean_nones(v) for v in data if v is not None]
return data return data
def save_project(proj: dict[str, Any], path: Union[str, Path], disc_data: Optional[dict[str, Any]] = None) -> None: def save_project(proj: Metadata, path: Union[str, Path], disc_data: Optional[Metadata] = None) -> None:
""" """
Save the project TOML. Save the project TOML.
If 'discussion' is present in proj, it is moved to the sibling history file. If 'discussion' is present in proj, it is moved to the sibling history file.
@@ -237,7 +250,7 @@ def save_project(proj: dict[str, Any], path: Union[str, Path], disc_data: Option
tomli_w.dump(disc_data, f) tomli_w.dump(disc_data, f)
# ── migration helper ───────────────────────────────────────────────────────── # ── migration helper ─────────────────────────────────────────────────────────
def migrate_from_legacy_config(cfg: dict[str, Any]) -> dict[str, Any]: def migrate_from_legacy_config(cfg: Metadata) -> Metadata:
"""Build a fresh project dict from a legacy flat config.toml. Does NOT save.""" """Build a fresh project dict from a legacy flat config.toml. Does NOT save."""
name = cfg.get("output", {}).get("namespace", "project") name = cfg.get("output", {}).get("namespace", "project")
proj = default_project(name) proj = default_project(name)
@@ -251,7 +264,7 @@ def migrate_from_legacy_config(cfg: dict[str, Any]) -> dict[str, Any]:
return proj return proj
# ── flat config for aggregate.run() ───────────────────────────────────────── # ── flat config for aggregate.run() ─────────────────────────────────────────
def flat_config(proj: dict[str, Any], disc_name: Optional[str] = None, track_id: Optional[str] = None) -> dict[str, Any]: def flat_config(proj: Metadata, disc_name: Optional[str] = None, track_id: Optional[str] = None) -> Metadata:
"""Return a flat config dict compatible with aggregate.run().""" """Return a flat config dict compatible with aggregate.run()."""
disc_sec = proj.get("discussion", {}) disc_sec = proj.get("discussion", {})
if track_id: if track_id:
@@ -326,7 +339,7 @@ def save_track_history(track_id: str, history: list[str], base_dir: Union[str, P
state.discussion = entries state.discussion = entries
save_track_state(track_id, state, base_dir) save_track_state(track_id, state, base_dir)
def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[dict[str, Any]]: def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[Metadata]:
""" """
Scans the conductor/tracks/ directory and returns a list of dictionaries Scans the conductor/tracks/ directory and returns a list of dictionaries
containing track metadata: 'id', 'title', 'status', 'complete', 'total', containing track metadata: 'id', 'title', 'status', 'complete', 'total',
@@ -343,13 +356,13 @@ def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[dict[str, Any]]:
if not tracks_dir.exists(): return [] if not tracks_dir.exists(): return []
from src.result_types import ErrorInfo, ErrorKind from src.result_types import ErrorInfo, ErrorKind
results: list[dict[str, Any]] = [] results: list[Metadata] = []
for entry in tracks_dir.iterdir(): for entry in tracks_dir.iterdir():
if not entry.is_dir(): continue if not entry.is_dir(): continue
track_id = entry.name track_id = entry.name
track_errors: list[dict[str, Any]] = [] track_errors: list[Metadata] = []
track_info: dict[str, Any] = { track_info: Metadata = {
"id": track_id, "id": track_id,
"title": track_id, "title": track_id,
"status": "unknown", "status": "unknown",