Private
Public Access
finished going through the entire gui_2.py minor sift through ai client
This commit is contained in:
+14
-63
@@ -79,10 +79,7 @@ events: EventEmitter = EventEmitter()
|
|||||||
#region: Provider Configuration
|
#region: Provider Configuration
|
||||||
|
|
||||||
def set_model_params(temp: float, max_tok: int, trunc_limit: int = 8000, top_p: float = 1.0) -> None:
|
def set_model_params(temp: float, max_tok: int, trunc_limit: int = 8000, top_p: float = 1.0) -> None:
|
||||||
"""
|
"""Sets global generation parameters like temperature and max tokens."""
|
||||||
Sets global generation parameters like temperature and max tokens.
|
|
||||||
[C: src/app_controller.py:AppController._handle_request_event, src/app_controller.py:_api_generate]
|
|
||||||
"""
|
|
||||||
global _temperature, _max_tokens, _history_trunc_limit, _top_p
|
global _temperature, _max_tokens, _history_trunc_limit, _top_p
|
||||||
_temperature = temp
|
_temperature = temp
|
||||||
_max_tokens = max_tok
|
_max_tokens = max_tok
|
||||||
@@ -150,17 +147,11 @@ _local_storage = threading.local()
|
|||||||
_tool_approval_modes: dict[str, str] = {}
|
_tool_approval_modes: dict[str, str] = {}
|
||||||
|
|
||||||
def get_current_tier() -> Optional[str]:
|
def get_current_tier() -> Optional[str]:
|
||||||
"""
|
"""Returns the current tier from thread-local storage."""
|
||||||
Returns the current tier from thread-local storage.
|
|
||||||
[C: src/app_controller.py:AppController._on_tool_log, tests/test_ai_client_concurrency.py:intercepted_append]
|
|
||||||
"""
|
|
||||||
return getattr(_local_storage, "current_tier", None)
|
return getattr(_local_storage, "current_tier", None)
|
||||||
|
|
||||||
def set_current_tier(tier: Optional[str]) -> None:
|
def set_current_tier(tier: Optional[str]) -> None:
|
||||||
"""
|
"""Sets the current tier in thread-local storage."""
|
||||||
Sets the current tier in thread-local storage.
|
|
||||||
[C: src/app_controller.py:AppController._handle_request_event, src/conductor_tech_lead.py:generate_tickets, src/multi_agent_conductor.py:run_worker_lifecycle, tests/test_ai_client_concurrency.py:run_t1, tests/test_ai_client_concurrency.py:run_t2, tests/test_mma_agent_focus_phase1.py:reset_tier, 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]
|
|
||||||
"""
|
|
||||||
_local_storage.current_tier = tier
|
_local_storage.current_tier = tier
|
||||||
|
|
||||||
# Increased to allow thorough code exploration before forcing a summary
|
# Increased to allow thorough code exploration before forcing a summary
|
||||||
@@ -198,10 +189,7 @@ _project_context_marker: str = ""
|
|||||||
#region: System Prompt Management
|
#region: System Prompt Management
|
||||||
|
|
||||||
def set_custom_system_prompt(prompt: str) -> None:
|
def set_custom_system_prompt(prompt: str) -> None:
|
||||||
"""
|
"""Sets a custom system prompt to be combined with the default instructions."""
|
||||||
Sets a custom system prompt to be combined with the default instructions.
|
|
||||||
[C: simulation/user_agent.py:UserSimAgent.generate_response, src/app_controller.py:AppController._do_generate, src/app_controller.py:AppController._handle_request_event, src/app_controller.py:_api_generate, src/conductor_tech_lead.py:generate_tickets, src/multi_agent_conductor.py:run_worker_lifecycle, src/orchestrator_pm.py:generate_tracks, tests/test_system_prompt_exposure.py:TestSystemPromptExposure.setUp]
|
|
||||||
"""
|
|
||||||
global _custom_system_prompt
|
global _custom_system_prompt
|
||||||
_custom_system_prompt = prompt
|
_custom_system_prompt = prompt
|
||||||
|
|
||||||
@@ -236,9 +224,6 @@ def _get_combined_system_prompt(preset: Optional[ToolPreset] = None, bias: Optio
|
|||||||
return base
|
return base
|
||||||
|
|
||||||
def get_combined_system_prompt(preset: Optional[ToolPreset] = None, bias: Optional[BiasProfile] = None) -> str:
|
def get_combined_system_prompt(preset: Optional[ToolPreset] = None, bias: Optional[BiasProfile] = None) -> str:
|
||||||
"""
|
|
||||||
[C: src/app_controller.py:AppController._do_generate, src/app_controller.py:AppController._handle_request_event]
|
|
||||||
"""
|
|
||||||
return _get_combined_system_prompt(preset, bias)
|
return _get_combined_system_prompt(preset, bias)
|
||||||
|
|
||||||
_comms_log: deque[dict[str, Any]] = deque(maxlen=1000)
|
_comms_log: deque[dict[str, Any]] = deque(maxlen=1000)
|
||||||
@@ -250,27 +235,16 @@ COMMS_CLAMP_CHARS: int = 300
|
|||||||
#region: Comms Log
|
#region: Comms Log
|
||||||
|
|
||||||
def get_comms_log_callback() -> Optional[Callable[[dict[str, Any]], None]]:
|
def get_comms_log_callback() -> Optional[Callable[[dict[str, Any]], None]]:
|
||||||
"""
|
|
||||||
Returns the comms log callback (thread-local with global fallback).
|
|
||||||
[C: src/multi_agent_conductor.py:run_worker_lifecycle]
|
|
||||||
"""
|
|
||||||
tl_cb = getattr(_local_storage, "comms_log_callback", None)
|
tl_cb = getattr(_local_storage, "comms_log_callback", None)
|
||||||
if tl_cb: return tl_cb
|
if tl_cb: return tl_cb
|
||||||
return comms_log_callback
|
return comms_log_callback
|
||||||
|
|
||||||
def set_comms_log_callback(cb: Optional[Callable[[dict[str, Any]], None]]) -> None:
|
def set_comms_log_callback(cb: Optional[Callable[[dict[str, Any]], None]]) -> None:
|
||||||
"""
|
|
||||||
Sets the comms log callback (both global and thread-local).
|
|
||||||
[C: src/app_controller.py:AppController._init_ai_and_hooks, src/multi_agent_conductor.py:run_worker_lifecycle]
|
|
||||||
"""
|
|
||||||
global comms_log_callback
|
global comms_log_callback
|
||||||
comms_log_callback = cb
|
comms_log_callback = cb
|
||||||
_local_storage.comms_log_callback = cb
|
_local_storage.comms_log_callback = cb
|
||||||
|
|
||||||
def _append_comms(direction: str, kind: str, payload: dict[str, Any]) -> None:
|
def _append_comms(direction: str, kind: str, payload: dict[str, Any]) -> None:
|
||||||
"""
|
|
||||||
[C: tests/test_ai_client_concurrency.py:run_t1, tests/test_ai_client_concurrency.py:run_t2, 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]
|
|
||||||
"""
|
|
||||||
entry: dict[str, Any] = {
|
entry: dict[str, Any] = {
|
||||||
"ts": datetime.datetime.now().strftime("%H:%M:%S"),
|
"ts": datetime.datetime.now().strftime("%H:%M:%S"),
|
||||||
"direction": direction,
|
"direction": direction,
|
||||||
@@ -287,27 +261,15 @@ def _append_comms(direction: str, kind: str, payload: dict[str, Any]) -> None:
|
|||||||
_cb(entry)
|
_cb(entry)
|
||||||
|
|
||||||
def get_comms_log() -> list[dict[str, Any]]:
|
def get_comms_log() -> list[dict[str, Any]]:
|
||||||
"""
|
|
||||||
[C: src/app_controller.py:AppController._bg_task, src/app_controller.py:AppController._recalculate_session_usage, src/app_controller.py:AppController._start_track_logic, src/multi_agent_conductor.py:run_worker_lifecycle, 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_token_usage.py:test_token_usage_tracking]
|
|
||||||
"""
|
|
||||||
return list(_comms_log)
|
return list(_comms_log)
|
||||||
|
|
||||||
def clear_comms_log() -> None:
|
def clear_comms_log() -> None:
|
||||||
"""
|
|
||||||
[C: src/app_controller.py:AppController._handle_reset_session, src/gui_2.py:App._render_comms_history_panel, src/gui_2.py:App._show_menus, tests/test_ai_client_concurrency.py:test_ai_client_tier_isolation, tests/test_token_usage.py:test_token_usage_tracking]
|
|
||||||
"""
|
|
||||||
_comms_log.clear()
|
_comms_log.clear()
|
||||||
|
|
||||||
def get_credentials_path() -> Path:
|
def get_credentials_path() -> Path:
|
||||||
"""
|
|
||||||
[C: src/mcp_client.py:_is_allowed]
|
|
||||||
"""
|
|
||||||
return Path(os.environ.get("SLOP_CREDENTIALS", str(Path(__file__).parent.parent / "credentials.toml")))
|
return Path(os.environ.get("SLOP_CREDENTIALS", str(Path(__file__).parent.parent / "credentials.toml")))
|
||||||
|
|
||||||
def _load_credentials() -> dict[str, Any]:
|
def _load_credentials() -> dict[str, Any]:
|
||||||
"""
|
|
||||||
[C: src/ai_server.py:_send_anthropic, src/ai_server.py:_send_deepseek, src/ai_server.py:_send_gemini, src/ai_server.py:_send_minimax, src/ai_server.py:handle_command, tests/test_deepseek_infra.py:test_credentials_error_mentions_deepseek, tests/test_minimax_provider.py:test_minimax_credentials_template]
|
|
||||||
"""
|
|
||||||
cred_path = get_credentials_path()
|
cred_path = get_credentials_path()
|
||||||
try:
|
try:
|
||||||
with open(cred_path, "rb") as f:
|
with open(cred_path, "rb") as f:
|
||||||
@@ -407,15 +369,13 @@ def _classify_minimax_error(exc: Exception, source: str = "ai_client.minimax") -
|
|||||||
return ErrorInfo(kind=ErrorKind.UNKNOWN, message=body, source=source, original=exc)
|
return ErrorInfo(kind=ErrorKind.UNKNOWN, message=body, source=source, original=exc)
|
||||||
|
|
||||||
def set_provider(provider: str, model: str, validate: bool = True) -> None:
|
def set_provider(provider: str, model: str, validate: bool = True) -> None:
|
||||||
"""
|
"""Updates the active LLM provider and model name.
|
||||||
Updates the active LLM provider and model name.
|
|
||||||
|
|
||||||
When validate is True (default), the model is checked against the provider's
|
When validate is True (default), the model is checked against the provider's
|
||||||
LIVE model list, which for gemini_cli/minimax means a blocking subprocess /
|
LIVE model list, which for gemini_cli/minimax means a blocking subprocess /
|
||||||
network call (and importing the provider SDK). Pass validate=False during
|
network call (and importing the provider SDK). Pass validate=False during
|
||||||
startup so the GUI's first frame is not blocked — AppController._fetch_models
|
startup so the GUI's first frame is not blocked — AppController._fetch_models
|
||||||
corrects the model against the live list shortly after, off the main thread.
|
corrects the model against the live list shortly after, off the main thread.
|
||||||
[C: src/app_controller.py:AppController._handle_reset_session, src/app_controller.py:AppController._init_ai_and_hooks, src/app_controller.py:AppController.current_model, src/app_controller.py:AppController.current_provider, src/app_controller.py:AppController.do_fetch, src/multi_agent_conductor.py:run_worker_lifecycle, src/orchestrator_pm.py:generate_tracks, 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_completion_logic, tests/test_deepseek_provider.py:test_deepseek_model_selection, tests/test_deepseek_provider.py:test_deepseek_payload_verification, tests/test_deepseek_provider.py:test_deepseek_reasoner_payload_verification, tests/test_deepseek_provider.py:test_deepseek_reasoning_logic, tests/test_deepseek_provider.py:test_deepseek_streaming, tests/test_deepseek_provider.py:test_deepseek_tool_calling, tests/test_gemini_cli_edge_cases.py:test_gemini_cli_loop_termination, 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_cli_parity_regression.py:test_send_invokes_adapter_send, tests/test_gui2_mcp.py:test_mcp_tool_call_is_dispatched, tests/test_minimax_provider.py:test_minimax_default_model, tests/test_minimax_provider.py:test_minimax_model_selection, tests/test_mma_agent_focus_phase1.py:test_append_comms_has_source_tier_key, tests/test_rag_integration.py:test_rag_integration, tests/test_tier4_interceptor.py:test_ai_client_passes_qa_callback, tests/test_tier4_interceptor.py:test_gemini_provider_passes_qa_callback_to_run_script, tests/test_token_usage.py:test_token_usage_tracking]
|
|
||||||
"""
|
"""
|
||||||
global _provider, _model
|
global _provider, _model
|
||||||
_provider = provider
|
_provider = provider
|
||||||
@@ -442,17 +402,11 @@ def set_provider(provider: str, model: str, validate: bool = True) -> None:
|
|||||||
_model = model
|
_model = model
|
||||||
|
|
||||||
def get_provider() -> str:
|
def get_provider() -> str:
|
||||||
"""
|
"""Returns the current active provider name."""
|
||||||
Returns the current active provider name.
|
|
||||||
[C: src/multi_agent_conductor.py:run_worker_lifecycle]
|
|
||||||
"""
|
|
||||||
return _provider
|
return _provider
|
||||||
|
|
||||||
def cleanup() -> None:
|
def cleanup() -> None:
|
||||||
"""
|
"""Performs cleanup operations like deleting server-side Gemini caches."""
|
||||||
Performs cleanup operations like deleting server-side Gemini caches.
|
|
||||||
[C: src/app_controller.py:AppController.clear_cache, src/app_controller.py:AppController.shutdown, tests/test_ai_cache_tracking.py:test_gemini_cache_tracking_cleanup, tests/test_log_registry.py:TestLogRegistry.tearDown, tests/test_project_serialization.py:TestProjectSerialization.tearDown]
|
|
||||||
"""
|
|
||||||
global _gemini_client, _gemini_cache, _gemini_cached_file_paths
|
global _gemini_client, _gemini_cache, _gemini_cached_file_paths
|
||||||
if _gemini_client and _gemini_cache:
|
if _gemini_client and _gemini_cache:
|
||||||
try:
|
try:
|
||||||
@@ -462,10 +416,7 @@ def cleanup() -> None:
|
|||||||
_gemini_cached_file_paths = []
|
_gemini_cached_file_paths = []
|
||||||
|
|
||||||
def reset_session() -> None:
|
def reset_session() -> None:
|
||||||
"""
|
"""Clears conversation history and resets provider-specific session state."""
|
||||||
Clears conversation history and resets provider-specific session state.
|
|
||||||
[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_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]
|
|
||||||
"""
|
|
||||||
global _gemini_client, _gemini_chat, _gemini_cache
|
global _gemini_client, _gemini_chat, _gemini_cache
|
||||||
global _gemini_cache_md_hash, _gemini_cache_created_at, _gemini_cached_file_paths
|
global _gemini_cache_md_hash, _gemini_cache_created_at, _gemini_cached_file_paths
|
||||||
global _anthropic_client, _anthropic_history
|
global _anthropic_client, _anthropic_history
|
||||||
@@ -2208,7 +2159,7 @@ def _ensure_grok_client() -> Any:
|
|||||||
_grok_client = openai.OpenAI(api_key=api_key, base_url="https://api.x.ai/v1")
|
_grok_client = openai.OpenAI(api_key=api_key, base_url="https://api.x.ai/v1")
|
||||||
return _grok_client
|
return _grok_client
|
||||||
|
|
||||||
def _send_grok_result(md_content: str, user_message: str, base_dir: str,
|
def _send_grok(md_content: str, user_message: str, base_dir: str,
|
||||||
file_items: list[dict[str, Any]] | None = None,
|
file_items: list[dict[str, Any]] | None = None,
|
||||||
discussion_history: str = "",
|
discussion_history: str = "",
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
@@ -2260,7 +2211,7 @@ def _list_grok_models() -> list[str]:
|
|||||||
from src.vendor_capabilities import list_models_for_vendor
|
from src.vendor_capabilities import list_models_for_vendor
|
||||||
return list_models_for_vendor("grok")
|
return list_models_for_vendor("grok")
|
||||||
|
|
||||||
def _send_minimax_result(md_content: str, user_message: str, base_dir: str,
|
def _send_minimax(md_content: str, user_message: str, base_dir: str,
|
||||||
file_items: list[dict[str, Any]] | None = None,
|
file_items: list[dict[str, Any]] | None = None,
|
||||||
discussion_history: str = "",
|
discussion_history: str = "",
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
@@ -2432,7 +2383,7 @@ def _ensure_llama_client() -> Any:
|
|||||||
_llama_client = openai.OpenAI(api_key=_llama_api_key, base_url=_llama_base_url)
|
_llama_client = openai.OpenAI(api_key=_llama_api_key, base_url=_llama_base_url)
|
||||||
return _llama_client
|
return _llama_client
|
||||||
|
|
||||||
def _send_llama_result(md_content: str, user_message: str, base_dir: str,
|
def _send_llama(md_content: str, user_message: str, base_dir: str,
|
||||||
file_items: list[dict[str, Any]] | None = None,
|
file_items: list[dict[str, Any]] | None = None,
|
||||||
discussion_history: str = "",
|
discussion_history: str = "",
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
@@ -2497,7 +2448,7 @@ def ollama_chat(
|
|||||||
resp = requests.post(f"{base_url}/api/chat", json=payload, timeout=120)
|
resp = requests.post(f"{base_url}/api/chat", json=payload, timeout=120)
|
||||||
return resp.json()
|
return resp.json()
|
||||||
|
|
||||||
def _send_llama_native_result(md_content: str, user_message: str, base_dir: str,
|
def _send_llama_native(md_content: str, user_message: str, base_dir: str,
|
||||||
file_items: list[dict[str, Any]] | None = None,
|
file_items: list[dict[str, Any]] | None = None,
|
||||||
discussion_history: str = "",
|
discussion_history: str = "",
|
||||||
stream: bool = False,
|
stream: bool = False,
|
||||||
@@ -2751,7 +2702,7 @@ def send_result(
|
|||||||
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
||||||
)
|
)
|
||||||
elif p == "minimax":
|
elif p == "minimax":
|
||||||
res = _send_minimax_result(
|
res = _send_minimax(
|
||||||
md_content, user_message, base_dir, file_items, discussion_history,
|
md_content, user_message, base_dir, file_items, discussion_history,
|
||||||
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
||||||
)
|
)
|
||||||
@@ -2771,7 +2722,7 @@ def send_result(
|
|||||||
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
||||||
)
|
)
|
||||||
elif p == "llama_native":
|
elif p == "llama_native":
|
||||||
res = _send_llama_native_result(
|
res = _send_llama_native(
|
||||||
md_content, user_message, base_dir, file_items, discussion_history,
|
md_content, user_message, base_dir, file_items, discussion_history,
|
||||||
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
stream, pre_tool_callback, qa_callback, stream_callback, patch_callback
|
||||||
)
|
)
|
||||||
|
|||||||
+110
-176
@@ -4513,13 +4513,11 @@ def render_discussion_entry(app: App, entry: dict, index: int) -> None:
|
|||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
def render_discussion_entry_read_mode(app: App, entry: dict, index: int) -> None:
|
def render_discussion_entry_read_mode(app: App, entry: dict, index: int) -> None:
|
||||||
"""
|
"""Renders a discussion entry in read-only mode.
|
||||||
Renders a discussion entry in read-only mode.
|
|
||||||
Parses the markdown content, isolates retrieved context sections (RAG chunks),
|
Parses the markdown content, isolates retrieved context sections (RAG chunks),
|
||||||
handles custom definition/AST links, and invokes the markdown syntax highlighter.
|
handles custom definition/AST links, and invokes the markdown syntax highlighter.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:extract_rag] -> [B:definitions?] => [I:markdown]`
|
||||||
`[I:extract_rag] -> [B:definitions?] => [I:markdown]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+-------------------------------------------------------------+
|
+-------------------------------------------------------------+
|
||||||
@@ -4578,16 +4576,10 @@ def render_discussion_entry_read_mode(app: App, entry: dict, index: int) -> None
|
|||||||
imgui.end_group()
|
imgui.end_group()
|
||||||
|
|
||||||
def render_history_window(app: App) -> None:
|
def render_history_window(app: App) -> None:
|
||||||
"""
|
"""Renders the Undo/Redo History window. Displays past UI snapshots in reverse chronological
|
||||||
Renders the Undo/Redo History window. Displays past UI snapshots in reverse chronological
|
|
||||||
order and allows reverting to prior states.
|
order and allows reverting to prior states.
|
||||||
|
|
||||||
State Mutations:
|
SSDL: `[I:history_list] -> [B:undo_redo_buttons] => [B:selectable_snapshots]`
|
||||||
app.show_windows['Undo/Redo History'] (updates visibility)
|
|
||||||
app.history (jumping/traversing history)
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:history_list] -> [B:undo_redo_buttons] => [B:selectable_snapshots]`
|
|
||||||
"""
|
"""
|
||||||
if not app.show_windows.get('Undo/Redo History', False):
|
if not app.show_windows.get('Undo/Redo History', False):
|
||||||
return
|
return
|
||||||
@@ -4613,15 +4605,10 @@ def render_history_window(app: App) -> None:
|
|||||||
else: iterate_history(history)
|
else: iterate_history(history)
|
||||||
|
|
||||||
def render_session_insights_panel(app: App) -> None:
|
def render_session_insights_panel(app: App) -> None:
|
||||||
"""
|
"""Renders session productivity insights, displaying total tokens, API call counts,
|
||||||
Renders session productivity insights, displaying total tokens, API call counts,
|
|
||||||
burn rates, total costs, completed ticket counts, and token efficiency.
|
burn rates, total costs, completed ticket counts, and token efficiency.
|
||||||
|
|
||||||
State Mutations:
|
SSDL: `[I:insights] -> [I:telemetry_texts]`
|
||||||
None directly.
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:insights] -> [I:telemetry_texts]`
|
|
||||||
"""
|
"""
|
||||||
if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_session_insights_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_session_insights_panel")
|
||||||
imgui.text_colored(C_LBL(), 'Session Insights')
|
imgui.text_colored(C_LBL(), 'Session Insights')
|
||||||
@@ -4638,16 +4625,10 @@ def render_session_insights_panel(app: App) -> None:
|
|||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_session_insights_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_session_insights_panel")
|
||||||
|
|
||||||
def render_prior_session_view(app: App) -> None:
|
def render_prior_session_view(app: App) -> None:
|
||||||
"""
|
"""Renders a historical read-only view of a loaded prior discussion session, complete
|
||||||
Renders a historical read-only view of a loaded prior discussion session, complete
|
|
||||||
with collapsing message bubbles and bubble colors.
|
with collapsing message bubbles and bubble colors.
|
||||||
|
|
||||||
State Mutations:
|
SSDL: `[I:prior_entries] -> [B:exit_button] -> [I:scroll_list]`
|
||||||
app.prior_disc_entries (collapsing/expanding bubbles)
|
|
||||||
app._comms_log_dirty (triggers log reload on exit)
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:prior_entries] -> [B:exit_button] -> [I:scroll_list]`
|
|
||||||
"""
|
"""
|
||||||
with imscope.style_color(imgui.Col_.child_bg, theme.get_color("bubble_vendor")):
|
with imscope.style_color(imgui.Col_.child_bg, theme.get_color("bubble_vendor")):
|
||||||
if imgui.button("Exit Prior Session"): app.controller.cb_exit_prior_session(); app._comms_log_dirty = True
|
if imgui.button("Exit Prior Session"): app.controller.cb_exit_prior_session(); app._comms_log_dirty = True
|
||||||
@@ -4674,26 +4655,20 @@ def render_prior_session_view(app: App) -> None:
|
|||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
def render_thinking_indicator(app: App) -> None:
|
def render_thinking_indicator(app: App) -> None:
|
||||||
"""
|
"""Renders a blinking red status indicator when the AI is currently executing,
|
||||||
Renders a blinking red status indicator when the AI is currently executing,
|
|
||||||
sending, streaming, or running shell commands.
|
sending, streaming, or running shell commands.
|
||||||
|
|
||||||
State Mutations:
|
SSDL: `[I:ai_status] -> [I:blinking_text]`
|
||||||
None.
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:ai_status] -> [I:blinking_text]`
|
|
||||||
"""
|
"""
|
||||||
is_thinking = app.ai_status in ['sending...', 'streaming...', 'running powershell...']
|
is_thinking = app.ai_status in ['sending...', 'streaming...', 'running powershell...']
|
||||||
if is_thinking:
|
if is_thinking:
|
||||||
val = math.sin(time.time() * 10 * math.pi)
|
val = math.sin(time.time() * 10 * math.pi)
|
||||||
alpha = 1.0 if val > 0 else 0.0
|
alpha = 1.0 if val > 0 else 0.0
|
||||||
c = theme.get_color("status_error", alpha=alpha)
|
c = theme.get_color("status_error", alpha=alpha)
|
||||||
imgui.text_colored(c, "THINKING..."); imgui.same_line()
|
imgui.text_colored(c, "THINKING...");
|
||||||
|
|
||||||
def _on_warmup_complete_callback(app: App, status: dict) -> None:
|
def _on_warmup_complete_callback(app: App, status: dict) -> None:
|
||||||
"""
|
"""Thread-safe callback registered with controller.on_warmup_complete()
|
||||||
Thread-safe callback registered with controller.on_warmup_complete()
|
|
||||||
during App._post_init. Records the completion timestamp; the
|
during App._post_init. Records the completion timestamp; the
|
||||||
indicator function uses it to show a brief "ready" tag. Also
|
indicator function uses it to show a brief "ready" tag. Also
|
||||||
appends a message to a lock-protected list that the indicator
|
appends a message to a lock-protected list that the indicator
|
||||||
@@ -4709,7 +4684,7 @@ def _on_warmup_complete_callback(app: App, status: dict) -> None:
|
|||||||
if failed: msg = f"Warmup finished with {len(failed)} failures ({total} modules)"
|
if failed: msg = f"Warmup finished with {len(failed)} failures ({total} modules)"
|
||||||
else: msg = f"All imports ready ({total} modules)"
|
else: msg = f"All imports ready ({total} modules)"
|
||||||
if not hasattr(app, "_warmup_toast_lock"):
|
if not hasattr(app, "_warmup_toast_lock"):
|
||||||
import threading as _threading
|
import threading as _threading #TODO(Ed): Review local import
|
||||||
app._warmup_toast_lock = _threading.Lock()
|
app._warmup_toast_lock = _threading.Lock()
|
||||||
with app._warmup_toast_lock:
|
with app._warmup_toast_lock:
|
||||||
if not hasattr(app, "_warmup_toast_messages"): app._warmup_toast_messages = []
|
if not hasattr(app, "_warmup_toast_messages"): app._warmup_toast_messages = []
|
||||||
@@ -4717,15 +4692,10 @@ def _on_warmup_complete_callback(app: App, status: dict) -> None:
|
|||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
def render_warmup_status_indicator(app: App) -> None:
|
def render_warmup_status_indicator(app: App) -> None:
|
||||||
"""
|
"""Renders a transient warmup status indicator in the main interface frame. Shows progress
|
||||||
Renders a transient warmup status indicator in the main interface frame. Shows progress
|
|
||||||
of AppController's background module imports.
|
of AppController's background module imports.
|
||||||
|
|
||||||
State Mutations:
|
SSDL: `[I:warmup_status] -> [I:status_text]`
|
||||||
None directly (reads controller warmup state).
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:warmup_status] -> [I:status_text]`
|
|
||||||
"""
|
"""
|
||||||
controller = getattr(app, "controller", None)
|
controller = getattr(app, "controller", None)
|
||||||
if controller is None: return
|
if controller is None: return
|
||||||
@@ -4784,16 +4754,10 @@ def render_synthesis_panel(app: App) -> None:
|
|||||||
app._handle_generate_send()
|
app._handle_generate_send()
|
||||||
|
|
||||||
def render_comms_history_panel(app: App) -> None:
|
def render_comms_history_panel(app: App) -> None:
|
||||||
"""
|
"""Renders the communications history log panel. Displays outgoing requests, incoming responses,
|
||||||
Renders the communications history log panel. Displays outgoing requests, incoming responses,
|
|
||||||
and tool call inputs/outputs in chronological order.
|
and tool call inputs/outputs in chronological order.
|
||||||
|
|
||||||
State Mutations:
|
SSDL: `[I:ai_status] -> [B:clear_exit_buttons] -> [I:direction_colors] -> [I:entries_scroll_list]`
|
||||||
app._comms_log_dirty (marks log for reload)
|
|
||||||
app._comms_log (clears log on user clear request)
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:ai_status] -> [B:clear_exit_buttons] -> [I:direction_colors] -> [I:entries_scroll_list]`
|
|
||||||
"""
|
"""
|
||||||
if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_comms_history_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_comms_history_panel")
|
||||||
st_col = theme.get_color("text_disabled")
|
st_col = theme.get_color("text_disabled")
|
||||||
@@ -4853,8 +4817,8 @@ def render_comms_history_panel(app: App) -> None:
|
|||||||
imgui.text_colored(theme.get_color("status_error"), f"[{ticket_id}]")
|
imgui.text_colored(theme.get_color("status_error"), f"[{ticket_id}]")
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
d_col_fn = DIR_COLORS.get(direction, C_VAL)
|
d_col_fn = DIR_COLORS.get(direction, C_VAL)
|
||||||
imgui.text_colored(d_col_fn(), direction); imgui.same_line()
|
|
||||||
k_col_fn = KIND_COLORS.get(kind, C_VAL)
|
k_col_fn = KIND_COLORS.get(kind, C_VAL)
|
||||||
|
imgui.text_colored(d_col_fn(), direction); imgui.same_line()
|
||||||
imgui.text_colored(k_col_fn(), kind); imgui.same_line()
|
imgui.text_colored(k_col_fn(), kind); imgui.same_line()
|
||||||
imgui.text_colored(C_LBL(), f"{provider}/{model}"); imgui.same_line()
|
imgui.text_colored(C_LBL(), f"{provider}/{model}"); imgui.same_line()
|
||||||
imgui.text_colored(C_SUB(), f"[{tier}]")
|
imgui.text_colored(C_SUB(), f"[{tier}]")
|
||||||
@@ -4903,12 +4867,10 @@ def render_comms_history_panel(app: App) -> None:
|
|||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_comms_history_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_comms_history_panel")
|
||||||
|
|
||||||
def render_takes_panel(app: App) -> None:
|
def render_takes_panel(app: App) -> None:
|
||||||
"""
|
"""Renders the Takes & Synthesis panel. Lists all discussion takes in a table,
|
||||||
Renders the Takes & Synthesis panel. Lists all discussion takes in a table,
|
|
||||||
allows switching or deleting them, and provides a multi-take synthesis workflow.
|
allows switching or deleting them, and provides a multi-take synthesis workflow.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:takes_table] -> [B:switch/delete] -> [I:synthesis_config] => [B:generate_synthesis]`
|
||||||
`[I:takes_table] -> [B:switch/delete] -> [I:synthesis_config] => [B:generate_synthesis]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -4931,10 +4893,8 @@ def render_takes_panel(app: App) -> None:
|
|||||||
imgui.text("Takes & Synthesis")
|
imgui.text("Takes & Synthesis")
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
discussions = app.project.get('discussion', {}).get('discussions', {})
|
discussions = app.project.get('discussion', {}).get('discussions', {})
|
||||||
if not isinstance(getattr(app, 'ui_synthesis_selected_takes', None), dict):
|
if not isinstance(getattr(app, 'ui_synthesis_selected_takes', None), dict): app.ui_synthesis_selected_takes = {name: False for name in discussions}
|
||||||
app.ui_synthesis_selected_takes = {name: False for name in discussions}
|
if not isinstance(getattr(app, 'ui_synthesis_prompt', None), str): app.ui_synthesis_prompt = ""
|
||||||
if not isinstance(getattr(app, 'ui_synthesis_prompt', None), str):
|
|
||||||
app.ui_synthesis_prompt = ""
|
|
||||||
if imgui.begin_table("takes_table", 3, imgui.TableFlags_.resizable | imgui.TableFlags_.borders):
|
if imgui.begin_table("takes_table", 3, imgui.TableFlags_.resizable | imgui.TableFlags_.borders):
|
||||||
imgui.table_setup_column("Name", imgui.TableColumnFlags_.width_stretch)
|
imgui.table_setup_column("Name", imgui.TableColumnFlags_.width_stretch)
|
||||||
imgui.table_setup_column("Entries", imgui.TableColumnFlags_.width_fixed, 80)
|
imgui.table_setup_column("Entries", imgui.TableColumnFlags_.width_fixed, 80)
|
||||||
@@ -4984,12 +4944,10 @@ def render_takes_panel(app: App) -> None:
|
|||||||
app._handle_generate_send()
|
app._handle_generate_send()
|
||||||
|
|
||||||
def render_discussion_entries(app: App) -> None:
|
def render_discussion_entries(app: App) -> None:
|
||||||
"""
|
"""Renders the scrollable list of all discussion entry bubbles. When a focus agent is
|
||||||
Renders the scrollable list of all discussion entry bubbles. When a focus agent is
|
|
||||||
active (ui_focus_agent), only entries matching that agent's persona (or User) are shown.
|
active (ui_focus_agent), only entries matching that agent's persona (or User) are shown.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:filter_by_agent?] -> [I:scroll_child] => [I:entry_bubbles]`
|
||||||
`[I:filter_by_agent?] -> [I:scroll_child] => [I:entry_bubbles]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5013,13 +4971,11 @@ def render_discussion_entries(app: App) -> None:
|
|||||||
if app._scroll_disc_to_bottom: imgui.set_scroll_here_y(1.0); app._scroll_disc_to_bottom = False
|
if app._scroll_disc_to_bottom: imgui.set_scroll_here_y(1.0); app._scroll_disc_to_bottom = False
|
||||||
|
|
||||||
def render_discussion_entry_controls(app: App) -> None:
|
def render_discussion_entry_controls(app: App) -> None:
|
||||||
"""
|
"""Renders the action buttons at the bottom of the discussion panel.
|
||||||
Renders the action buttons at the bottom of the discussion panel.
|
|
||||||
Handles adding entries, expanding/collapsing all bubbles, clearing, saving,
|
Handles adding entries, expanding/collapsing all bubbles, clearing, saving,
|
||||||
compressing logs, and configuring auto-history checkpoints.
|
compressing logs, and configuring auto-history checkpoints.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:buttons] -> [B:clicks] => [S:entries_or_config]`
|
||||||
`[I:buttons] -> [B:clicks] => [S:entries_or_config]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+-------------------------------------------------------------+
|
+-------------------------------------------------------------+
|
||||||
@@ -5051,12 +5007,10 @@ def render_discussion_entry_controls(app: App) -> None:
|
|||||||
app.ai_status = f"history truncated to {app.ui_disc_truncate_pairs} pairs"
|
app.ai_status = f"history truncated to {app.ui_disc_truncate_pairs} pairs"
|
||||||
|
|
||||||
def render_discussion_metadata(app: App) -> None:
|
def render_discussion_metadata(app: App) -> None:
|
||||||
"""
|
"""Renders per-discussion metadata: cumulative token counts, git commit association,
|
||||||
Renders per-discussion metadata: cumulative token counts, git commit association,
|
|
||||||
last updated timestamp, and controls for creating, renaming, and deleting discussions.
|
last updated timestamp, and controls for creating, renaming, and deleting discussions.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:token_totals] -> [I:commit_row] -> [I:timestamp] -> [B:create/rename/delete]`
|
||||||
`[I:token_totals] -> [I:commit_row] -> [I:timestamp] -> [B:create/rename/delete]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5099,13 +5053,11 @@ def render_discussion_metadata(app: App) -> None:
|
|||||||
if imgui.button("Delete"): app._delete_discussion(app.active_discussion)
|
if imgui.button("Delete"): app._delete_discussion(app.active_discussion)
|
||||||
|
|
||||||
def render_discussion_panel(app: App) -> None:
|
def render_discussion_panel(app: App) -> None:
|
||||||
"""
|
"""Top-level discussion panel compositor. Renders the thinking indicator,
|
||||||
Top-level discussion panel compositor. Renders the thinking indicator,
|
|
||||||
prior-session read-only view (if active), discussion selector, entry controls,
|
prior-session read-only view (if active), discussion selector, entry controls,
|
||||||
role list, and scrollable entry bubbles.
|
role list, and scrollable entry bubbles.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:thinking_indicator] -> [I:prior_view?] | [I:selector] -> [I:controls] -> [I:roles] -> [I:entries]`
|
||||||
`[I:thinking_indicator] -> [I:prior_view?] | [I:selector] -> [I:controls] -> [I:roles] -> [I:entries]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5142,12 +5094,10 @@ def render_discussion_panel(app: App) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def render_discussion_roles(app: App) -> None:
|
def render_discussion_roles(app: App) -> None:
|
||||||
"""
|
"""Renders the collapsible Roles section. Lists current roles with an [X] delete button
|
||||||
Renders the collapsible Roles section. Lists current roles with an [X] delete button
|
|
||||||
per entry, and exposes an input field for adding new roles.
|
per entry, and exposes an input field for adding new roles.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[B:collapsing_header] => [I:roles_list] -> [B:add_role]`
|
||||||
`[B:collapsing_header] => [I:roles_list] -> [B:add_role]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5171,13 +5121,11 @@ def render_discussion_roles(app: App) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def render_discussion_selector(app: App) -> None:
|
def render_discussion_selector(app: App) -> None:
|
||||||
"""
|
"""Renders the collapsible Discussions selector. Shows a combo-box for choosing
|
||||||
Renders the collapsible Discussions selector. Shows a combo-box for choosing
|
|
||||||
the active base discussion, a tab-bar for takes, a Synthesis tab, promote/track
|
the active base discussion, a tab-bar for takes, a Synthesis tab, promote/track
|
||||||
controls, and the discussion metadata row.
|
controls, and the discussion metadata row.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[B:collapsing_header] => [I:combo_base] -> [I:takes_tabs] -> [B:promote?] -> [B:track?] -> [I:metadata]`
|
||||||
`[B:collapsing_header] => [I:combo_base] -> [I:takes_tabs] -> [B:promote?] -> [B:track?] -> [I:metadata]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5189,11 +5137,9 @@ def render_discussion_selector(app: App) -> None:
|
|||||||
| [new-name] [Create] [Rename] [Delete] |
|
| [new-name] [Create] [Rename] [Delete] |
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
"""
|
"""
|
||||||
if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open):
|
if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return
|
||||||
return
|
|
||||||
names = app._get_discussion_names(); grouped = {}
|
names = app._get_discussion_names(); grouped = {}
|
||||||
for name in names:
|
for name in names: base = name.split("_take_")[0]; grouped.setdefault(base, []).append(name)
|
||||||
base = name.split("_take_")[0]; grouped.setdefault(base, []).append(name)
|
|
||||||
active_base = app.active_discussion.split("_take_")[0]
|
active_base = app.active_discussion.split("_take_")[0]
|
||||||
if active_base not in grouped: active_base = names[0] if names else ""
|
if active_base not in grouped: active_base = names[0] if names else ""
|
||||||
base_names = sorted(grouped.keys())
|
base_names = sorted(grouped.keys())
|
||||||
@@ -5237,8 +5183,7 @@ def render_discussion_selector(app: App) -> None:
|
|||||||
return
|
return
|
||||||
|
|
||||||
def render_discussion_tab(app: App) -> None:
|
def render_discussion_tab(app: App) -> None:
|
||||||
"""
|
"""Renders the Discussion tab content. Comprises a resizable top pane (history/entries)
|
||||||
Renders the Discussion tab content. Comprises a resizable top pane (history/entries)
|
|
||||||
and a bottom pane with a draggable splitter bar, pop-out checkboxes, and
|
and a bottom pane with a draggable splitter bar, pop-out checkboxes, and
|
||||||
inline Message/Response tabs.
|
inline Message/Response tabs.
|
||||||
|
|
||||||
@@ -5297,12 +5242,10 @@ def render_discussion_tab(app: App) -> None:
|
|||||||
#region: Operations Monitor
|
#region: Operations Monitor
|
||||||
|
|
||||||
def render_operations_hub(app: App) -> None:
|
def render_operations_hub(app: App) -> None:
|
||||||
"""
|
"""Top-level Operations Monitor hub. Houses pop-out checkboxes for Tool Calls, Usage Analytics,
|
||||||
Top-level Operations Monitor hub. Houses pop-out checkboxes for Tool Calls, Usage Analytics,
|
|
||||||
and External Tools, then a tab-bar for all ops sub-panels.
|
and External Tools, then a tab-bar for all ops sub-panels.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[B:popout_toggles] -> [I:tab_bar] => [I:active_tab_content]`
|
||||||
`[B:popout_toggles] -> [I:tab_bar] => [I:active_tab_content]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5356,12 +5299,10 @@ def render_operations_hub(app: App) -> None:
|
|||||||
if exp: render_vendor_state(app)
|
if exp: render_vendor_state(app)
|
||||||
|
|
||||||
def render_vendor_state(app: App) -> None:
|
def render_vendor_state(app: App) -> None:
|
||||||
"""
|
"""Renders the Operations Hub > Vendor State panel. Displays per-vendor health metrics
|
||||||
Renders the Operations Hub > Vendor State panel. Displays per-vendor health metrics
|
|
||||||
(model name, cache state, token budget, connection status) in a colour-coded table.
|
(model name, cache state, token budget, connection status) in a colour-coded table.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:metrics_table] => [I:state_column]`
|
||||||
`[I:metrics_table] => [I:state_column]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5392,12 +5333,10 @@ def render_vendor_state(app: App) -> None:
|
|||||||
imgui.end_table()
|
imgui.end_table()
|
||||||
|
|
||||||
def render_message_panel(app: App) -> None:
|
def render_message_panel(app: App) -> None:
|
||||||
"""
|
"""Renders user message text input area, exposing buttons to generate assistant responses,
|
||||||
Renders user message text input area, exposing buttons to generate assistant responses,
|
|
||||||
inject contextual files, or reset active conversation sessions.
|
inject contextual files, or reset active conversation sessions.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:live_indicator] -> [I:input_textbox] -> [B:gen_send_buttons] -> [B:inject_reset]`
|
||||||
`[I:live_indicator] -> [I:input_textbox] -> [B:gen_send_buttons] -> [B:inject_reset]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5448,12 +5387,10 @@ def render_message_panel(app: App) -> None:
|
|||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_message_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_message_panel")
|
||||||
|
|
||||||
def render_response_panel(app: App) -> None:
|
def render_response_panel(app: App) -> None:
|
||||||
"""
|
"""Renders assistant stream output panel. Renders thinking traces, markdown segments,
|
||||||
Renders assistant stream output panel. Renders thinking traces, markdown segments,
|
|
||||||
and exports active responses to history entries.
|
and exports active responses to history entries.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:response_text] -> [I:thinking_trace] -> [I:markdown_view] => [B:export_to_history]`
|
||||||
`[I:response_text] -> [I:thinking_trace] -> [I:markdown_view] => [B:export_to_history]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5506,12 +5443,10 @@ def render_response_panel(app: App) -> None:
|
|||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_response_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_response_panel")
|
||||||
|
|
||||||
def render_tool_calls_panel(app: App) -> None:
|
def render_tool_calls_panel(app: App) -> None:
|
||||||
"""
|
"""Renders tool call execution log. Displays script execution details, status codes,
|
||||||
Renders tool call execution log. Displays script execution details, status codes,
|
|
||||||
and outputs in a scrollable table. Clicking a row opens the full call in the Text Viewer.
|
and outputs in a scrollable table. Clicking a row opens the full call in the Text Viewer.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:tool_log] -> [B:clear_button] => [I:calls_table]`
|
||||||
`[I:tool_log] -> [B:clear_button] => [I:calls_table]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5580,12 +5515,10 @@ def render_tool_calls_panel(app: App) -> None:
|
|||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_tool_calls_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_tool_calls_panel")
|
||||||
|
|
||||||
def render_external_tools_panel(app: App) -> None:
|
def render_external_tools_panel(app: App) -> None:
|
||||||
"""
|
"""Renders the External MCPs panel. Shows server health indicators, a [Refresh] button,
|
||||||
Renders the External MCPs panel. Shows server health indicators, a [Refresh] button,
|
|
||||||
and a table of all registered external MCP tool names, servers, and descriptions.
|
and a table of all registered external MCP tool names, servers, and descriptions.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL Shape: `[B:refresh] -> [I:server_status_badges] -> [I:tools_table]`
|
||||||
`[B:refresh] -> [I:server_status_badges] -> [I:tools_table]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5642,13 +5575,11 @@ def render_external_tools_panel(app: App) -> None:
|
|||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_external_tools_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_external_tools_panel")
|
||||||
|
|
||||||
def render_text_viewer_window(app: App) -> None:
|
def render_text_viewer_window(app: App) -> None:
|
||||||
"""
|
"""Renders the standalone text/code/markdown viewer window. Supports four rendering modes
|
||||||
Renders the standalone text/code/markdown viewer window. Supports four rendering modes
|
|
||||||
based on content type: markdown (rendered), slice editor (line-click range selection),
|
based on content type: markdown (rendered), slice editor (line-click range selection),
|
||||||
syntax-highlighted code (CodeEditor widget), and plain text (scrollable).
|
syntax-highlighted code (CodeEditor widget), and plain text (scrollable).
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:mode_dispatch] => [I:markdown] | [I:slice_editor] | [I:code_editor] | [I:plain_text]`
|
||||||
`[I:mode_dispatch] => [I:markdown] | [I:slice_editor] | [I:code_editor] | [I:plain_text]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5729,7 +5660,9 @@ def render_text_viewer_window(app: App) -> None:
|
|||||||
imgui.separator()
|
imgui.separator()
|
||||||
if imgui.button("Copy"): imgui.set_clipboard_text(app.text_viewer_content)
|
if imgui.button("Copy"): imgui.set_clipboard_text(app.text_viewer_content)
|
||||||
imgui.same_line(); _, app.text_viewer_wrap = imgui.checkbox("Word Wrap", app.text_viewer_wrap)
|
imgui.same_line(); _, app.text_viewer_wrap = imgui.checkbox("Word Wrap", app.text_viewer_wrap)
|
||||||
|
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
renderer = markdown_helper.get_renderer(); tv_type = getattr(app, "text_viewer_type", "text")
|
renderer = markdown_helper.get_renderer(); tv_type = getattr(app, "text_viewer_type", "text")
|
||||||
if tv_type == 'markdown':
|
if tv_type == 'markdown':
|
||||||
with imscope.child("tv_md_scroll", -1, -1, True): markdown_helper.render(app.text_viewer_content, context_id='text_viewer')
|
with imscope.child("tv_md_scroll", -1, -1, True): markdown_helper.render(app.text_viewer_content, context_id='text_viewer')
|
||||||
@@ -5768,12 +5701,10 @@ def render_text_viewer_window(app: App) -> None:
|
|||||||
imgui.end()
|
imgui.end()
|
||||||
|
|
||||||
def render_patch_modal(app: App) -> None:
|
def render_patch_modal(app: App) -> None:
|
||||||
"""
|
"""Renders the Apply Patch? modal. Shows files to be modified, a syntax-highlighted
|
||||||
Renders the Apply Patch? modal. Shows files to be modified, a syntax-highlighted
|
|
||||||
diff preview, and action buttons to open in an external editor, apply, or reject.
|
diff preview, and action buttons to open in an external editor, apply, or reject.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:files_list] -> [I:diff_preview] => [B:open_external | B:apply | B:reject]`
|
||||||
`[I:files_list] -> [I:diff_preview] => [B:open_external | B:apply | B:reject]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5836,12 +5767,10 @@ def render_patch_modal(app: App) -> None:
|
|||||||
imgui.close_current_popup()
|
imgui.close_current_popup()
|
||||||
|
|
||||||
def render_external_editor_panel(app: App) -> None:
|
def render_external_editor_panel(app: App) -> None:
|
||||||
"""
|
"""Renders the External Editor configuration panel. Lists configured editors
|
||||||
Renders the External Editor configuration panel. Lists configured editors
|
|
||||||
from config.toml, shows the current default, and allows setting a new default.
|
from config.toml, shows the current default, and allows setting a new default.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:editors_list] -> [B:set_default] => [I:config_hint?]`
|
||||||
`[I:editors_list] -> [B:set_default] => [I:config_hint?]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -5970,13 +5899,11 @@ def render_approve_script_modal(app: App) -> None:
|
|||||||
#region: Misc Tools
|
#region: Misc Tools
|
||||||
|
|
||||||
def render_theme_panel(app: App) -> None:
|
def render_theme_panel(app: App) -> None:
|
||||||
"""
|
"""Renders the Theme configuration window. Covers palette selection, panel pop-out toggles,
|
||||||
Renders the Theme configuration window. Covers palette selection, panel pop-out toggles,
|
|
||||||
font path/size, DPI scale, transparency sliders, background shader, CRT filter, and
|
font path/size, DPI scale, transparency sliders, background shader, CRT filter, and
|
||||||
per-palette tone mapping (brightness/contrast/gamma).
|
per-palette tone mapping (brightness/contrast/gamma).
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:palette_combo] -> [B:panel_popout_toggles] -> [I:font_config] -> [I:scale_sliders] -> [I:tone_mapping]`
|
||||||
`[I:palette_combo] -> [B:panel_popout_toggles] -> [I:font_config] -> [I:scale_sliders] -> [I:tone_mapping]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -6099,13 +6026,13 @@ def render_theme_panel(app: App) -> None:
|
|||||||
imgui.end()
|
imgui.end()
|
||||||
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_theme_panel")
|
if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_theme_panel")
|
||||||
|
|
||||||
|
#NOTE(Ed): This was part of an experiment to see what the ai could generate and if it could figure how to add
|
||||||
|
# A post-process mechanism to the gui (it did not).
|
||||||
def render_shader_live_editor(app: App) -> None:
|
def render_shader_live_editor(app: App) -> None:
|
||||||
"""
|
"""Renders the Shader Live Editor window. Exposes real-time sliders for CRT curvature,
|
||||||
Renders the Shader Live Editor window. Exposes real-time sliders for CRT curvature,
|
|
||||||
scanline intensity, and bloom threshold.
|
scanline intensity, and bloom threshold.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:shader_uniforms] => [I:slider_controls]`
|
||||||
`[I:shader_uniforms] => [I:slider_controls]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -6114,8 +6041,6 @@ def render_shader_live_editor(app: App) -> None:
|
|||||||
| Scanline Intensity: [==|=========] 0.20 |
|
| Scanline Intensity: [==|=========] 0.20 |
|
||||||
| Bloom Threshold: [===|========] 0.30 |
|
| Bloom Threshold: [===|========] 0.30 |
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
|
|
||||||
[C: tests/test_shader_live_editor.py:test_shader_live_editor_renders]
|
|
||||||
"""
|
"""
|
||||||
if app.show_windows.get('Shader Editor', False):
|
if app.show_windows.get('Shader Editor', False):
|
||||||
with imscope.window('Shader Editor', app.show_windows['Shader Editor']) as (exp, opened):
|
with imscope.window('Shader Editor', app.show_windows['Shader Editor']) as (exp, opened):
|
||||||
@@ -6125,13 +6050,12 @@ def render_shader_live_editor(app: App) -> None:
|
|||||||
changed_scan, app.shader_uniforms['scanline'] = imgui.slider_float('Scanline Intensity', app.shader_uniforms['scanline'], 0.0, 1.0)
|
changed_scan, app.shader_uniforms['scanline'] = imgui.slider_float('Scanline Intensity', app.shader_uniforms['scanline'], 0.0, 1.0)
|
||||||
changed_bloom, app.shader_uniforms['bloom'] = imgui.slider_float('Bloom Threshold', app.shader_uniforms['bloom'], 0.0, 1.0)
|
changed_bloom, app.shader_uniforms['bloom'] = imgui.slider_float('Bloom Threshold', app.shader_uniforms['bloom'], 0.0, 1.0)
|
||||||
|
|
||||||
|
#TODO(Ed): This shouldn't be here, it needs to be within the test that uitlizes it.
|
||||||
def render_markdown_test(app: App) -> None:
|
def render_markdown_test(app: App) -> None:
|
||||||
"""
|
"""Renders a static markdown test panel used to validate the markdown renderer.
|
||||||
Renders a static markdown test panel used to validate the markdown renderer.
|
|
||||||
Displays headers, bold/italic text, lists, links, and a code block.
|
Displays headers, bold/italic text, lists, links, and a code block.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:static_md_sample] => [I:rendered_markdown]`
|
||||||
`[I:static_md_sample] => [I:rendered_markdown]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -6184,7 +6108,6 @@ def render_error_tint(app: App) -> None:
|
|||||||
imgui.text_colored(theme.get_color("status_error"), "HOT RELOAD ERROR")
|
imgui.text_colored(theme.get_color("status_error"), "HOT RELOAD ERROR")
|
||||||
imgui.text_wrapped(HotReloader.last_error or "Unknown error")
|
imgui.text_wrapped(HotReloader.last_error or "Unknown error")
|
||||||
|
|
||||||
|
|
||||||
def render_project_stale_tint(app: App) -> None:
|
def render_project_stale_tint(app: App) -> None:
|
||||||
"""Renders a yellow/amber tint overlay when the project is mid-switch.
|
"""Renders a yellow/amber tint overlay when the project is mid-switch.
|
||||||
|
|
||||||
@@ -6205,15 +6128,12 @@ def render_project_stale_tint(app: App) -> None:
|
|||||||
imgui.text_wrapped(f"Loading: {Path(pending).stem if pending else '?'}")
|
imgui.text_wrapped(f"Loading: {Path(pending).stem if pending else '?'}")
|
||||||
imgui.text_wrapped("UI is read-only until the switch completes. You can still browse tabs.")
|
imgui.text_wrapped("UI is read-only until the switch completes. You can still browse tabs.")
|
||||||
|
|
||||||
|
|
||||||
def render_heavy_text(app: App, label: str, content: str, id_suffix: str = "") -> None:
|
def render_heavy_text(app: App, label: str, content: str, id_suffix: str = "") -> None:
|
||||||
"""
|
"""Renders a labelled heavy-text field: a [+] button to pop content into the Text Viewer,
|
||||||
Renders a labelled heavy-text field: a [+] button to pop content into the Text Viewer,
|
|
||||||
a truncated inline preview, and a scrollable child panel showing the full content
|
a truncated inline preview, and a scrollable child panel showing the full content
|
||||||
(markdown-rendered for message/text/content/system labels; plain text otherwise).
|
(markdown-rendered for message/text/content/system labels; plain text otherwise).
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[B:pop_out_viewer] -> [I:label_preview] -> [I:content_child]`
|
||||||
`[B:pop_out_viewer] -> [I:label_preview] -> [I:content_child]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -6248,7 +6168,6 @@ def render_heavy_text(app: App, label: str, content: str, id_suffix: str = "") -
|
|||||||
else:
|
else:
|
||||||
imgui.text_colored(theme.get_color("text"), content)
|
imgui.text_colored(theme.get_color("text"), content)
|
||||||
|
|
||||||
|
|
||||||
#endregion: Misc Tools
|
#endregion: Misc Tools
|
||||||
|
|
||||||
#region: MMA
|
#region: MMA
|
||||||
@@ -6562,10 +6481,8 @@ def render_mma_global_controls(app: App) -> None:
|
|||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
if imgui.button("Reload GUI"):
|
if imgui.button("Reload GUI"):
|
||||||
success = app._trigger_hot_reload()
|
success = app._trigger_hot_reload()
|
||||||
if success:
|
if success: imgui.text_colored(theme.get_color("status_success"), "Reloaded!")
|
||||||
imgui.text_colored(theme.get_color("status_success"), "Reloaded!")
|
else: imgui.text_colored(theme.get_color("status_error"), f"Error: {app._hot_reload_error or 'Unknown'}")
|
||||||
else:
|
|
||||||
imgui.text_colored(theme.get_color("status_error"), f"Error: {app._hot_reload_error or 'Unknown'}")
|
|
||||||
imgui.same_line(); imgui.text_disabled("(Ctrl+Alt+R)")
|
imgui.same_line(); imgui.text_disabled("(Ctrl+Alt+R)")
|
||||||
|
|
||||||
def render_mma_usage_section(app: App) -> None:
|
def render_mma_usage_section(app: App) -> None:
|
||||||
@@ -6593,8 +6510,23 @@ def render_mma_usage_section(app: App) -> None:
|
|||||||
imgui.table_setup_column("Tier"); imgui.table_setup_column("Model"); imgui.table_setup_column("Input"); imgui.table_setup_column("Output"); imgui.table_setup_column("Est. Cost"); imgui.table_headers_row()
|
imgui.table_setup_column("Tier"); imgui.table_setup_column("Model"); imgui.table_setup_column("Input"); imgui.table_setup_column("Output"); imgui.table_setup_column("Est. Cost"); imgui.table_headers_row()
|
||||||
total_cost = 0.0
|
total_cost = 0.0
|
||||||
for tier, stats in app.mma_tier_usage.items():
|
for tier, stats in app.mma_tier_usage.items():
|
||||||
imgui.table_next_row(); imgui.table_next_column(); imgui.text(tier); imgui.table_next_column(); model = stats.get('model', 'unknown'); imgui.text(model); imgui.table_next_column(); in_t = stats.get('input', 0); imgui.text(f"{in_t:,}"); imgui.table_next_column(); out_t = stats.get('output', 0); imgui.text(f"{out_t:,}"); imgui.table_next_column(); cost = cost_tracker.estimate_cost(model, in_t, out_t); total_cost += cost; imgui.text(f"${cost:,.4f}")
|
imgui.table_next_row();
|
||||||
imgui.table_next_row(); imgui.table_set_bg_color(imgui.TableBgTarget_.row_bg0, imgui.get_color_u32(imgui.Col_.plot_lines_hovered)); imgui.table_next_column(); imgui.text("TOTAL"); imgui.table_next_column(); imgui.text(""); imgui.table_next_column(); imgui.text(""); imgui.table_next_column(); imgui.text(""); imgui.table_next_column(); imgui.text(f"${total_cost:,.4f}"); imgui.end_table()
|
imgui.table_next_column();
|
||||||
|
imgui.text(tier); imgui.table_next_column();
|
||||||
|
model = stats.get('model', 'unknown'); imgui.text(model); imgui.table_next_column();
|
||||||
|
in_t = stats.get('input', 0); imgui.text(f"{in_t:,}"); imgui.table_next_column();
|
||||||
|
out_t = stats.get('output', 0); imgui.text(f"{out_t:,}"); imgui.table_next_column();
|
||||||
|
cost = cost_tracker.estimate_cost(model, in_t, out_t);
|
||||||
|
total_cost += cost; imgui.text(f"${cost:,.4f}")
|
||||||
|
imgui.table_next_row();
|
||||||
|
imgui.table_set_bg_color(imgui.TableBgTarget_.row_bg0, imgui.get_color_u32(imgui.Col_.plot_lines_hovered)); imgui.table_next_column();
|
||||||
|
imgui.text("TOTAL"); imgui.table_next_column();
|
||||||
|
imgui.text(""); imgui.table_next_column();
|
||||||
|
imgui.text(""); imgui.table_next_column();
|
||||||
|
imgui.text(""); imgui.table_next_column();
|
||||||
|
imgui.text(f"${total_cost:,.4f}");
|
||||||
|
imgui.end_table()
|
||||||
|
|
||||||
if imgui.collapsing_header("Tier Model Config"):
|
if imgui.collapsing_header("Tier Model Config"):
|
||||||
for tier in app.mma_tier_usage.keys():
|
for tier in app.mma_tier_usage.keys():
|
||||||
imgui.text(f"{tier}:"); imgui.same_line(); curr_model, curr_prov = app.mma_tier_usage[tier].get("model", "unknown"), app.mma_tier_usage[tier].get("provider", "gemini")
|
imgui.text(f"{tier}:"); imgui.same_line(); curr_model, curr_prov = app.mma_tier_usage[tier].get("model", "unknown"), app.mma_tier_usage[tier].get("provider", "gemini")
|
||||||
@@ -6631,12 +6563,10 @@ def render_mma_usage_section(app: App) -> None:
|
|||||||
imgui.pop_item_width()
|
imgui.pop_item_width()
|
||||||
|
|
||||||
def render_mma_ticket_editor(app: App) -> None:
|
def render_mma_ticket_editor(app: App) -> None:
|
||||||
"""
|
"""Renders the ticket detail editor panel, letting the user modify priority, target,
|
||||||
Renders the ticket detail editor panel, letting the user modify priority, target,
|
|
||||||
and persona override, mark a ticket complete, or delete it.
|
and persona override, mark a ticket complete, or delete it.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I:ticket_details] -> [B:combo_selectors] => [B:action_buttons]`
|
||||||
`[I:ticket_details] -> [B:combo_selectors] => [B:action_buttons]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -6661,19 +6591,21 @@ def render_mma_ticket_editor(app: App) -> None:
|
|||||||
imgui.text(f"Target: {ticket.get('target_file', '')}"); imgui.text(f"Depends on: {', '.join(ticket.get('depends_on', []))}")
|
imgui.text(f"Target: {ticket.get('target_file', '')}"); imgui.text(f"Depends on: {', '.join(ticket.get('depends_on', []))}")
|
||||||
personas = getattr(app.controller, 'personas', {}); curr_pers = ticket.get('persona_id', '')
|
personas = getattr(app.controller, 'personas', {}); curr_pers = ticket.get('persona_id', '')
|
||||||
imgui.text("Persona Override:"); imgui.same_line()
|
imgui.text("Persona Override:"); imgui.same_line()
|
||||||
pers_opts = ["None"] + sorted(personas.keys()); curr_idx = pers_opts.index(curr_pers) + 1 if curr_pers in pers_opts else 0
|
pers_opts = ["None"] + sorted(personas.keys());
|
||||||
|
curr_idx = pers_opts.index(curr_pers) + 1 if curr_pers in pers_opts else 0
|
||||||
_, curr_idx = imgui.combo(f"##ticket_persona_{ticket.get('id')}", curr_idx, pers_opts)
|
_, curr_idx = imgui.combo(f"##ticket_persona_{ticket.get('id')}", curr_idx, pers_opts)
|
||||||
ticket['persona_id'] = None if curr_idx == 0 or pers_opts[curr_idx] == "None" else pers_opts[curr_idx]
|
ticket['persona_id'] = None if curr_idx == 0 or pers_opts[curr_idx] == "None" else pers_opts[curr_idx]
|
||||||
if imgui.button(f"Mark Complete##{app.ui_selected_ticket_id}"): ticket['status'] = 'done'; app._push_mma_state_update()
|
if imgui.button(f"Mark Complete##{app.ui_selected_ticket_id}"): ticket['status'] = 'done'; app._push_mma_state_update()
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
if imgui.button(f"Delete##{app.ui_selected_ticket_id}"): app.active_tickets = [t for t in app.active_tickets if str(t.get('id', '')) != app.ui_selected_ticket_id]; app.ui_selected_ticket_id = None; app._push_mma_state_update()
|
if imgui.button(f"Delete##{app.ui_selected_ticket_id}"):
|
||||||
|
app.active_tickets = [t for t in app.active_tickets if str(t.get('id', '')) != app.ui_selected_ticket_id]
|
||||||
|
app.ui_selected_ticket_id = None
|
||||||
|
app._push_mma_state_update()
|
||||||
|
|
||||||
def render_mma_agent_streams(app: App) -> None:
|
def render_mma_agent_streams(app: App) -> None:
|
||||||
"""
|
"""Renders the agent execution stream panels in a tabbed view for Tier 1, 2, 3, and 4.
|
||||||
Renders the agent execution stream panels in a tabbed view for Tier 1, 2, 3, and 4.
|
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL: `[I] -> [B:tab_bar] => [I:stream_panels]`
|
||||||
`[I] -> [B:tab_bar] => [I:stream_panels]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -6689,7 +6621,8 @@ def render_mma_agent_streams(app: App) -> None:
|
|||||||
for tier, label, sep_flag_attr in [("Tier 1", "Tier 1", "ui_separate_tier1"), ("Tier 2", "Tier 2 (Tech Lead)", "ui_separate_tier2"), ("Tier 3", None, "ui_separate_tier3"), ("Tier 4", "Tier 4 (QA)", "ui_separate_tier4")]:
|
for tier, label, sep_flag_attr in [("Tier 1", "Tier 1", "ui_separate_tier1"), ("Tier 2", "Tier 2 (Tech Lead)", "ui_separate_tier2"), ("Tier 3", None, "ui_separate_tier3"), ("Tier 4", "Tier 4 (QA)", "ui_separate_tier4")]:
|
||||||
with imscope.tab_item(tier) as (exp, _):
|
with imscope.tab_item(tier) as (exp, _):
|
||||||
if exp:
|
if exp:
|
||||||
sep_val = getattr(app, sep_flag_attr); ch, new_val = imgui.checkbox(f"Pop Out {tier}", sep_val)
|
sep_val = getattr(app, sep_flag_attr);
|
||||||
|
ch, new_val = imgui.checkbox(f"Pop Out {tier}", sep_val)
|
||||||
if ch:
|
if ch:
|
||||||
setattr(app, sep_flag_attr, new_val)
|
setattr(app, sep_flag_attr, new_val)
|
||||||
app.show_windows[f"{tier}: Strategy" if tier == "Tier 1" else (f"{tier}: Tech Lead" if tier == "Tier 2" else (f"{tier}: Workers" if tier == "Tier 3" else f"{tier}: QA"))] = new_val
|
app.show_windows[f"{tier}: Strategy" if tier == "Tier 1" else (f"{tier}: Tech Lead" if tier == "Tier 2" else (f"{tier}: Workers" if tier == "Tier 3" else f"{tier}: QA"))] = new_val
|
||||||
@@ -6753,16 +6686,13 @@ def render_tier_stream_panel(app: App, tier_key: str, stream_key: str | None) ->
|
|||||||
for key in tier3_keys:
|
for key in tier3_keys:
|
||||||
ticket_id = key.split(": ", 1)[-1] if ": " in key else key
|
ticket_id = key.split(": ", 1)[-1] if ": " in key else key
|
||||||
status = worker_status.get(key, "unknown")
|
status = worker_status.get(key, "unknown")
|
||||||
if status == "running":
|
if status == "running": imgui.text_colored(theme.get_color("status_warning"), f"{ticket_id} [{status}]")
|
||||||
imgui.text_colored(theme.get_color("status_warning"), f"{ticket_id} [{status}]")
|
elif status == "completed": imgui.text_colored(theme.get_color("status_success"), f"{ticket_id} [{status}]")
|
||||||
elif status == "completed":
|
elif status == "failed": imgui.text_colored(theme.get_color("status_error"), f"{ticket_id} [{status}]")
|
||||||
imgui.text_colored(theme.get_color("status_success"), f"{ticket_id} [{status}]")
|
else: imgui.text( f"{ticket_id} [{status}]")
|
||||||
elif status == "failed":
|
|
||||||
imgui.text_colored(theme.get_color("status_error"), f"{ticket_id} [{status}]")
|
|
||||||
else:
|
|
||||||
imgui.text(f"{ticket_id} [{status}]")
|
|
||||||
imgui.begin_child(f"##tier3_{ticket_id}_scroll", imgui.ImVec2(-1, 150), True)
|
imgui.begin_child(f"##tier3_{ticket_id}_scroll", imgui.ImVec2(-1, 150), True)
|
||||||
render_selectable_label(app, f'stream_t3_{ticket_id}', app.mma_streams[key], width=-1, multiline=True, height=0)
|
render_selectable_label(app, f'stream_t3_{ticket_id}', app.mma_streams[key], width=-1, multiline=True, height=0)
|
||||||
|
#NOTE(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
if len(app.mma_streams[key]) != app._tier_stream_last_len.get(key, -1):
|
if len(app.mma_streams[key]) != app._tier_stream_last_len.get(key, -1):
|
||||||
imgui.set_scroll_here_y(1.0)
|
imgui.set_scroll_here_y(1.0)
|
||||||
@@ -6797,7 +6727,7 @@ def render_track_proposal_modal(app: App) -> None:
|
|||||||
if app._show_track_proposal_modal:
|
if app._show_track_proposal_modal:
|
||||||
imgui.open_popup("Track Proposal")
|
imgui.open_popup("Track Proposal")
|
||||||
if imgui.begin_popup_modal("Track Proposal", True, imgui.WindowFlags_.always_auto_resize)[0]:
|
if imgui.begin_popup_modal("Track Proposal", True, imgui.WindowFlags_.always_auto_resize)[0]:
|
||||||
from src import shaders
|
from src import shaders #TODO(Ed): Review local import
|
||||||
p_min = imgui.get_window_pos()
|
p_min = imgui.get_window_pos()
|
||||||
p_max = imgui.ImVec2(p_min.x + imgui.get_window_size().x, p_min.y + imgui.get_window_size().y)
|
p_max = imgui.ImVec2(p_min.x + imgui.get_window_size().x, p_min.y + imgui.get_window_size().y)
|
||||||
# Render soft shadow behind the modal
|
# Render soft shadow behind the modal
|
||||||
@@ -7069,15 +6999,18 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
|||||||
app._push_mma_state_update()
|
app._push_mma_state_update()
|
||||||
break
|
break
|
||||||
ed.end_delete()
|
ed.end_delete()
|
||||||
|
|
||||||
# Validate DAG after any changes
|
# Validate DAG after any changes
|
||||||
|
#TODO(Ed): Exception(Review)
|
||||||
try:
|
try:
|
||||||
from src.dag_engine import TrackDAG
|
from src.dag_engine import TrackDAG #TODO(Ed) Reivew local import
|
||||||
ticket_dicts = [{'id': str(t.get('id', '')), 'depends_on': t.get('depends_on', [])} for t in app.active_tickets]
|
ticket_dicts = [{'id': str(t.get('id', '')), 'depends_on': t.get('depends_on', [])} for t in app.active_tickets]
|
||||||
temp_dag = TrackDAG(ticket_dicts)
|
temp_dag = TrackDAG(ticket_dicts)
|
||||||
if temp_dag.has_cycle():
|
if temp_dag.has_cycle():
|
||||||
imgui.open_popup("Cycle Detected!")
|
imgui.open_popup("Cycle Detected!")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ed.end()
|
ed.end()
|
||||||
# 5. Add Ticket Form
|
# 5. Add Ticket Form
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
@@ -7089,6 +7022,7 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
|
|||||||
for t in app.active_tickets:
|
for t in app.active_tickets:
|
||||||
tid = t.get('id', '')
|
tid = t.get('id', '')
|
||||||
if tid.startswith('T-'):
|
if tid.startswith('T-'):
|
||||||
|
#TODO(Ed): Exception(Review)
|
||||||
try: max_id = max(max_id, int(tid[2:]))
|
try: max_id = max(max_id, int(tid[2:]))
|
||||||
except: pass
|
except: pass
|
||||||
app.ui_new_ticket_id = f"T-{max_id + 1:03d}"
|
app.ui_new_ticket_id = f"T-{max_id + 1:03d}"
|
||||||
|
|||||||
Reference in New Issue
Block a user