fixing
This commit is contained in:
@@ -18,6 +18,10 @@ paths = [
|
||||
]
|
||||
active = "C:\\projects\\manual_slop\\tests\\artifacts\\temp_project.toml"
|
||||
|
||||
[gui]
|
||||
separate_message_panel = false
|
||||
separate_response_panel = false
|
||||
|
||||
[gui.show_windows]
|
||||
"Context Hub" = true
|
||||
"Files & Media" = true
|
||||
@@ -29,6 +33,8 @@ active = "C:\\projects\\manual_slop\\tests\\artifacts\\temp_project.toml"
|
||||
"Tier 4: QA" = true
|
||||
"Discussion Hub" = true
|
||||
"Operations Hub" = true
|
||||
Message = false
|
||||
Response = false
|
||||
Theme = true
|
||||
"Log Management" = true
|
||||
Diagnostics = true
|
||||
|
||||
@@ -79,7 +79,7 @@ DockId=0x0000000F,2
|
||||
|
||||
[Window][Theme]
|
||||
Pos=0,17
|
||||
Size=692,824
|
||||
Size=705,927
|
||||
Collapsed=0
|
||||
DockId=0x00000005,1
|
||||
|
||||
@@ -89,14 +89,14 @@ Size=900,700
|
||||
Collapsed=0
|
||||
|
||||
[Window][Diagnostics]
|
||||
Pos=694,17
|
||||
Size=257,794
|
||||
Pos=707,17
|
||||
Size=1141,657
|
||||
Collapsed=0
|
||||
DockId=0x00000010,1
|
||||
DockId=0x0000001A,0
|
||||
|
||||
[Window][Context Hub]
|
||||
Pos=0,17
|
||||
Size=692,824
|
||||
Size=705,927
|
||||
Collapsed=0
|
||||
DockId=0x00000005,0
|
||||
|
||||
@@ -107,26 +107,26 @@ Collapsed=0
|
||||
DockId=0x0000000D,0
|
||||
|
||||
[Window][Discussion Hub]
|
||||
Pos=953,17
|
||||
Size=727,1082
|
||||
Pos=1850,17
|
||||
Size=1137,1311
|
||||
Collapsed=0
|
||||
DockId=0x00000012,0
|
||||
DockId=0x00000013,0
|
||||
|
||||
[Window][Operations Hub]
|
||||
Pos=694,17
|
||||
Size=257,794
|
||||
Pos=707,676
|
||||
Size=1141,652
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
DockId=0x0000001B,0
|
||||
|
||||
[Window][Files & Media]
|
||||
Pos=0,843
|
||||
Size=692,357
|
||||
Pos=0,946
|
||||
Size=705,1191
|
||||
Collapsed=0
|
||||
DockId=0x00000006,1
|
||||
|
||||
[Window][AI Settings]
|
||||
Pos=0,843
|
||||
Size=692,357
|
||||
Pos=0,946
|
||||
Size=705,1191
|
||||
Collapsed=0
|
||||
DockId=0x00000006,0
|
||||
|
||||
@@ -136,16 +136,16 @@ Size=416,325
|
||||
Collapsed=0
|
||||
|
||||
[Window][MMA Dashboard]
|
||||
Pos=953,1101
|
||||
Size=727,99
|
||||
Pos=2989,17
|
||||
Size=851,2120
|
||||
Collapsed=0
|
||||
DockId=0x00000013,0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Log Management]
|
||||
Pos=953,17
|
||||
Size=727,1082
|
||||
Pos=2989,17
|
||||
Size=851,2120
|
||||
Collapsed=0
|
||||
DockId=0x00000012,1
|
||||
DockId=0x00000004,1
|
||||
|
||||
[Window][Track Proposal]
|
||||
Pos=709,326
|
||||
@@ -153,28 +153,28 @@ Size=262,209
|
||||
Collapsed=0
|
||||
|
||||
[Window][Tier 1: Strategy]
|
||||
Pos=953,1101
|
||||
Size=727,99
|
||||
Pos=707,1330
|
||||
Size=463,807
|
||||
Collapsed=0
|
||||
DockId=0x00000013,1
|
||||
DockId=0x00000014,0
|
||||
|
||||
[Window][Tier 2: Tech Lead]
|
||||
Pos=953,1101
|
||||
Size=727,99
|
||||
Pos=1172,1330
|
||||
Size=730,807
|
||||
Collapsed=0
|
||||
DockId=0x00000013,2
|
||||
DockId=0x00000016,0
|
||||
|
||||
[Window][Tier 4: QA]
|
||||
Pos=694,813
|
||||
Size=257,387
|
||||
Pos=2453,1330
|
||||
Size=534,807
|
||||
Collapsed=0
|
||||
DockId=0x00000011,1
|
||||
DockId=0x00000019,0
|
||||
|
||||
[Window][Tier 3: Workers]
|
||||
Pos=694,813
|
||||
Size=257,387
|
||||
Pos=1904,1330
|
||||
Size=547,807
|
||||
Collapsed=0
|
||||
DockId=0x00000011,0
|
||||
DockId=0x00000018,0
|
||||
|
||||
[Window][Approve PowerShell Command]
|
||||
Pos=649,435
|
||||
@@ -209,26 +209,34 @@ Column 2 Weight=1.0000
|
||||
Column 3 Weight=1.0000
|
||||
|
||||
[Docking][Data]
|
||||
DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y
|
||||
DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A
|
||||
DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02
|
||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,17 Size=1680,1183 Split=Y
|
||||
DockNode ID=0x0000000C Parent=0xAFC85805 SizeRef=1362,1041 Split=X Selected=0x5D11106F
|
||||
DockNode ID=0x00000003 Parent=0x0000000C SizeRef=711,1183 Split=X
|
||||
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=Y Selected=0xF4139CA2
|
||||
DockNode ID=0x00000002 Parent=0x0000000B SizeRef=1029,1119 Split=X Selected=0xF4139CA2
|
||||
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=452,858 Split=Y Selected=0x8CA2375C
|
||||
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,824 Selected=0xF4139CA2
|
||||
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,995 CentralNode=1 Selected=0x7BD57D6A
|
||||
DockNode ID=0x0000000E Parent=0x00000002 SizeRef=257,858 Split=Y Selected=0x418C7449
|
||||
DockNode ID=0x00000010 Parent=0x0000000E SizeRef=868,1065 Selected=0xB4CBF21A
|
||||
DockNode ID=0x00000011 Parent=0x0000000E SizeRef=868,520 Selected=0x5CDB7A4B
|
||||
DockNode ID=0x00000001 Parent=0x0000000B SizeRef=1029,775 Selected=0x8B4EBFA6
|
||||
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
|
||||
DockNode ID=0x00000004 Parent=0x0000000C SizeRef=727,1183 Split=Y Selected=0x2C0206CE
|
||||
DockNode ID=0x00000012 Parent=0x00000004 SizeRef=905,1082 Selected=0x6F2B5B04
|
||||
DockNode ID=0x00000013 Parent=0x00000004 SizeRef=905,99 Selected=0xBB346584
|
||||
DockNode ID=0x0000000F Parent=0xAFC85805 SizeRef=1362,451 Selected=0xDD6419BC
|
||||
DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y
|
||||
DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A
|
||||
DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02
|
||||
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,17 Size=3840,2120 Split=Y
|
||||
DockNode ID=0x0000000C Parent=0xAFC85805 SizeRef=1362,1041 Split=X Selected=0x5D11106F
|
||||
DockNode ID=0x00000003 Parent=0x0000000C SizeRef=2987,1183 Split=X
|
||||
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=Y Selected=0xF4139CA2
|
||||
DockNode ID=0x00000002 Parent=0x0000000B SizeRef=1029,1119 Split=X Selected=0xF4139CA2
|
||||
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=705,858 Split=Y Selected=0x8CA2375C
|
||||
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,927 Selected=0xF4139CA2
|
||||
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,1191 CentralNode=1 Selected=0x7BD57D6A
|
||||
DockNode ID=0x0000000E Parent=0x00000002 SizeRef=2280,858 Split=Y Selected=0x418C7449
|
||||
DockNode ID=0x00000010 Parent=0x0000000E SizeRef=868,1311 Split=X Selected=0x418C7449
|
||||
DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1141,402 Split=Y Selected=0xB4CBF21A
|
||||
DockNode ID=0x0000001A Parent=0x00000012 SizeRef=1141,657 Selected=0xB4CBF21A
|
||||
DockNode ID=0x0000001B Parent=0x00000012 SizeRef=1141,652 Selected=0x418C7449
|
||||
DockNode ID=0x00000013 Parent=0x00000010 SizeRef=1137,402 Selected=0x6F2B5B04
|
||||
DockNode ID=0x00000011 Parent=0x0000000E SizeRef=868,807 Split=X Selected=0x5CDB7A4B
|
||||
DockNode ID=0x00000014 Parent=0x00000011 SizeRef=463,837 Selected=0xBB346584
|
||||
DockNode ID=0x00000015 Parent=0x00000011 SizeRef=1815,837 Split=X Selected=0x5CDB7A4B
|
||||
DockNode ID=0x00000016 Parent=0x00000015 SizeRef=730,837 Selected=0x390E7942
|
||||
DockNode ID=0x00000017 Parent=0x00000015 SizeRef=1083,837 Split=X Selected=0x655BC6E9
|
||||
DockNode ID=0x00000018 Parent=0x00000017 SizeRef=547,874 Selected=0x655BC6E9
|
||||
DockNode ID=0x00000019 Parent=0x00000017 SizeRef=534,874 Selected=0x5CDB7A4B
|
||||
DockNode ID=0x00000001 Parent=0x0000000B SizeRef=1029,775 Selected=0x8B4EBFA6
|
||||
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
|
||||
DockNode ID=0x00000004 Parent=0x0000000C SizeRef=851,1183 Selected=0x3AEC3498
|
||||
DockNode ID=0x0000000F Parent=0xAFC85805 SizeRef=1362,451 Selected=0xDD6419BC
|
||||
|
||||
;;;<<<Layout_655921752_Default>>>;;;
|
||||
;;;<<<HelloImGui_Misc>>>;;;
|
||||
|
||||
@@ -159,3 +159,211 @@ PROMPT:
|
||||
role: tool
|
||||
Here are the results: {"content": "done"}
|
||||
------------------
|
||||
--- MOCK INVOKED ---
|
||||
ARGS: ['C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py', '-m', 'gemini-2.5-flash-lite', '--prompt', '', '--output-format', 'stream-json']
|
||||
PROMPT:
|
||||
You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). When calling file/directory tools, always use the 'path' parameter for the target path. When asked to create or edit files, prefer targeted edits over full rewrites. Always explain what you are doing before invoking the tool.
|
||||
|
||||
When writing or rewriting large files (especially those containing quotes, backticks, or special characters), avoid python -c with inline strings. Instead: (1) write a .py helper script to disk using a PS here-string (@'...'@ for literal content), (2) run it with `python <script>`, (3) delete the helper. For small targeted edits, use PowerShell's (Get-Content) / .Replace() / Set-Content or Add-Content directly.
|
||||
|
||||
When making function calls using tools that accept array or object parameters ensure those are structured using JSON. For example:
|
||||
When you need to verify a change, rely on the exit code and stdout/stderr from the tool — the user's context files are automatically refreshed after every tool call, so you do NOT need to re-read files that are already provided in the <context> block.
|
||||
|
||||
<context>
|
||||
|
||||
</context>
|
||||
|
||||
[DISCUSSION HISTORY]
|
||||
|
||||
## Discussion History
|
||||
|
||||
### Discussion Excerpt 1
|
||||
|
||||
@2026-03-06T19:34:06
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 430.6ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 2
|
||||
|
||||
@2026-03-06T19:34:41
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 58.2ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 3
|
||||
|
||||
@2026-03-06T19:38:51
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 409.3ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 4
|
||||
|
||||
@2026-03-06T19:40:43
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 64.5ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 5
|
||||
|
||||
@2026-03-06T19:41:13
|
||||
System:
|
||||
[PERFORMANCE ALERT] CPU usage high: 94.0%. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 6
|
||||
|
||||
@2026-03-06T19:41:59
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 440.6ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 7
|
||||
|
||||
@2026-03-06T19:43:42
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 58.3ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 8
|
||||
|
||||
@2026-03-06T19:45:01
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 435.0ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
test
|
||||
------------------
|
||||
--- MOCK INVOKED ---
|
||||
ARGS: ['C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py', '-m', 'gemini-2.5-flash-lite', '--prompt', '', '--resume', 'mock-session-default', '--output-format', 'stream-json']
|
||||
PROMPT:
|
||||
You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). When calling file/directory tools, always use the 'path' parameter for the target path. When asked to create or edit files, prefer targeted edits over full rewrites. Always explain what you are doing before invoking the tool.
|
||||
|
||||
When writing or rewriting large files (especially those containing quotes, backticks, or special characters), avoid python -c with inline strings. Instead: (1) write a .py helper script to disk using a PS here-string (@'...'@ for literal content), (2) run it with `python <script>`, (3) delete the helper. For small targeted edits, use PowerShell's (Get-Content) / .Replace() / Set-Content or Add-Content directly.
|
||||
|
||||
When making function calls using tools that accept array or object parameters ensure those are structured using JSON. For example:
|
||||
When you need to verify a change, rely on the exit code and stdout/stderr from the tool — the user's context files are automatically refreshed after every tool call, so you do NOT need to re-read files that are already provided in the <context> block.
|
||||
|
||||
<context>
|
||||
|
||||
</context>
|
||||
|
||||
nice job
|
||||
------------------
|
||||
--- MOCK INVOKED ---
|
||||
ARGS: ['C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py', '-m', 'gemini-2.5-flash-lite', '--prompt', '', '--output-format', 'stream-json']
|
||||
PROMPT:
|
||||
You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). When calling file/directory tools, always use the 'path' parameter for the target path. When asked to create or edit files, prefer targeted edits over full rewrites. Always explain what you are doing before invoking the tool.
|
||||
|
||||
When writing or rewriting large files (especially those containing quotes, backticks, or special characters), avoid python -c with inline strings. Instead: (1) write a .py helper script to disk using a PS here-string (@'...'@ for literal content), (2) run it with `python <script>`, (3) delete the helper. For small targeted edits, use PowerShell's (Get-Content) / .Replace() / Set-Content or Add-Content directly.
|
||||
|
||||
When making function calls using tools that accept array or object parameters ensure those are structured using JSON. For example:
|
||||
When you need to verify a change, rely on the exit code and stdout/stderr from the tool — the user's context files are automatically refreshed after every tool call, so you do NOT need to re-read files that are already provided in the <context> block.
|
||||
|
||||
<context>
|
||||
|
||||
</context>
|
||||
|
||||
[DISCUSSION HISTORY]
|
||||
|
||||
## Discussion History
|
||||
|
||||
### Discussion Excerpt 1
|
||||
|
||||
@2026-03-06T19:34:06
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 430.6ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 2
|
||||
|
||||
@2026-03-06T19:34:41
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 58.2ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 3
|
||||
|
||||
@2026-03-06T19:38:51
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 409.3ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 4
|
||||
|
||||
@2026-03-06T19:40:43
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 64.5ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 5
|
||||
|
||||
@2026-03-06T19:41:13
|
||||
System:
|
||||
[PERFORMANCE ALERT] CPU usage high: 94.0%. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 6
|
||||
|
||||
@2026-03-06T19:41:59
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 440.6ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 7
|
||||
|
||||
@2026-03-06T19:43:42
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 58.3ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 8
|
||||
|
||||
@2026-03-06T19:45:01
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 435.0ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 9
|
||||
|
||||
@2026-03-06T19:45:31
|
||||
System:
|
||||
[PERFORMANCE ALERT] CPU usage high: 114.1%. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 10
|
||||
|
||||
@2026-03-06T19:52:00
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 538.9ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
### Discussion Excerpt 11
|
||||
|
||||
@2026-03-06T19:52:08
|
||||
System:
|
||||
[PERFORMANCE ALERT] Frame time high: 419.0ms. Please consider optimizing recent changes or reducing load.
|
||||
|
||||
---
|
||||
|
||||
test
|
||||
------------------
|
||||
|
||||
@@ -24,6 +24,7 @@ import threading
|
||||
import requests # type: ignore[import-untyped]
|
||||
from typing import Optional, Callable, Any, List, Union, cast, Iterable
|
||||
import os
|
||||
from pathlib import Path
|
||||
from src import project_manager
|
||||
from src import file_cache
|
||||
from src import mcp_client
|
||||
@@ -157,8 +158,11 @@ def get_comms_log() -> list[dict[str, Any]]:
|
||||
def clear_comms_log() -> None:
|
||||
_comms_log.clear()
|
||||
|
||||
def get_credentials_path() -> Path:
|
||||
return Path(os.environ.get("SLOP_CREDENTIALS", "credentials.toml"))
|
||||
|
||||
def _load_credentials() -> dict[str, Any]:
|
||||
cred_path = os.environ.get("SLOP_CREDENTIALS", "credentials.toml")
|
||||
cred_path = get_credentials_path()
|
||||
try:
|
||||
with open(cred_path, "rb") as f:
|
||||
return tomllib.load(f)
|
||||
|
||||
@@ -148,10 +148,10 @@ class AppController:
|
||||
"last_latency": 0.0
|
||||
}
|
||||
self.mma_tier_usage: Dict[str, Dict[str, Any]] = {
|
||||
"Tier 1": {"input": 0, "output": 0, "model": "gemini-3.1-pro-preview"},
|
||||
"Tier 2": {"input": 0, "output": 0, "model": "gemini-3-flash-preview"},
|
||||
"Tier 3": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"},
|
||||
"Tier 4": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"},
|
||||
"Tier 1": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-3.1-pro-preview"},
|
||||
"Tier 2": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-3-flash-preview"},
|
||||
"Tier 3": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-2.5-flash-lite"},
|
||||
"Tier 4": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-2.5-flash-lite"},
|
||||
}
|
||||
self.perf_monitor: performance_monitor.PerformanceMonitor = performance_monitor.PerformanceMonitor()
|
||||
self._pending_gui_tasks: List[Dict[str, Any]] = []
|
||||
@@ -195,6 +195,8 @@ class AppController:
|
||||
self.ui_global_system_prompt: str = ""
|
||||
self.ui_agent_tools: Dict[str, bool] = {}
|
||||
self.available_models: List[str] = []
|
||||
self.all_available_models: Dict[str, List[str]] = {} # provider -> list of models
|
||||
self._autofocus_response_tab = False
|
||||
self.proposed_tracks: List[Dict[str, Any]] = []
|
||||
self._show_track_proposal_modal: bool = False
|
||||
self.ai_status: str = 'idle'
|
||||
@@ -401,6 +403,8 @@ class AppController:
|
||||
self._trigger_blink = True
|
||||
if not stream_id:
|
||||
self._token_stats_dirty = True
|
||||
if not is_streaming:
|
||||
self._autofocus_response_tab = True
|
||||
# ONLY add to history when turn is complete
|
||||
if self.ui_auto_add_history and not stream_id and not is_streaming:
|
||||
role = payload.get("role", "AI")
|
||||
@@ -408,7 +412,7 @@ class AppController:
|
||||
self._pending_history_adds.append({
|
||||
"role": role,
|
||||
"content": self.ai_response,
|
||||
"collapsed": False,
|
||||
"collapsed": True,
|
||||
"ts": project_manager.now_ts()
|
||||
})
|
||||
elif action in ("mma_stream", "mma_stream_append"):
|
||||
@@ -429,7 +433,19 @@ class AppController:
|
||||
payload = task # Fallback to task if payload missing or wrong type
|
||||
self.mma_status = payload.get("status", "idle")
|
||||
self.active_tier = payload.get("active_tier")
|
||||
self.mma_tier_usage = payload.get("tier_usage", self.mma_tier_usage)
|
||||
|
||||
# Preserve existing model/provider config if not explicitly in payload
|
||||
new_usage = payload.get("tier_usage", {})
|
||||
for tier, data in new_usage.items():
|
||||
if tier in self.mma_tier_usage:
|
||||
# Update usage counts but keep selected model/provider if not in update
|
||||
self.mma_tier_usage[tier]["input"] = data.get("input", self.mma_tier_usage[tier]["input"])
|
||||
self.mma_tier_usage[tier]["output"] = data.get("output", self.mma_tier_usage[tier]["output"])
|
||||
if "model" in data: self.mma_tier_usage[tier]["model"] = data["model"]
|
||||
if "provider" in data: self.mma_tier_usage[tier]["provider"] = data["provider"]
|
||||
else:
|
||||
self.mma_tier_usage[tier] = data
|
||||
|
||||
self.active_tickets = payload.get("tickets", [])
|
||||
track_data = payload.get("track")
|
||||
if track_data:
|
||||
@@ -622,6 +638,8 @@ class AppController:
|
||||
"Tier 4: QA": True,
|
||||
"Discussion Hub": True,
|
||||
"Operations Hub": True,
|
||||
"Message": False,
|
||||
"Response": False,
|
||||
"Theme": True,
|
||||
"Log Management": False,
|
||||
"Diagnostics": False,
|
||||
@@ -725,7 +743,14 @@ class AppController:
|
||||
|
||||
def do_fetch() -> None:
|
||||
try:
|
||||
models_list = ai_client.list_models(provider)
|
||||
for p in self.PROVIDERS:
|
||||
try:
|
||||
self.all_available_models[p] = ai_client.list_models(p)
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"[DEBUG] Error fetching models for {p}: {e}\n")
|
||||
self.all_available_models[p] = []
|
||||
|
||||
models_list = self.all_available_models.get(provider, [])
|
||||
self.available_models = models_list
|
||||
if self.current_model not in models_list and models_list:
|
||||
self.current_model = models_list[0]
|
||||
@@ -851,7 +876,7 @@ class AppController:
|
||||
self._pending_history_adds.append({
|
||||
"role": "User",
|
||||
"content": event.prompt,
|
||||
"collapsed": False,
|
||||
"collapsed": True,
|
||||
"ts": project_manager.now_ts()
|
||||
})
|
||||
# Clear response area for new turn
|
||||
@@ -896,6 +921,13 @@ class AppController:
|
||||
entry["local_ts"] = time.time()
|
||||
kind = entry.get("kind")
|
||||
payload = entry.get("payload", {})
|
||||
|
||||
if kind == "response" and "usage" in payload:
|
||||
u = payload["usage"]
|
||||
for k in ["input_tokens", "output_tokens", "cache_read_input_tokens", "cache_creation_input_tokens", "total_tokens"]:
|
||||
if k in u:
|
||||
self.session_usage[k] += u.get(k, 0) or 0
|
||||
|
||||
if kind in ("tool_result", "tool_call"):
|
||||
role = "Tool" if kind == "tool_result" else "Vendor API"
|
||||
content = ""
|
||||
@@ -1173,7 +1205,7 @@ class AppController:
|
||||
self._pending_history_adds.append({
|
||||
"role": "User",
|
||||
"content": user_msg,
|
||||
"collapsed": False,
|
||||
"collapsed": True,
|
||||
"ts": project_manager.now_ts()
|
||||
})
|
||||
try:
|
||||
@@ -1183,7 +1215,7 @@ class AppController:
|
||||
self._pending_history_adds.append({
|
||||
"role": "AI",
|
||||
"content": resp,
|
||||
"collapsed": False,
|
||||
"collapsed": True,
|
||||
"ts": project_manager.now_ts()
|
||||
})
|
||||
self._recalculate_session_usage()
|
||||
@@ -1669,6 +1701,7 @@ class AppController:
|
||||
# Save MMA State
|
||||
mma_sec = proj.setdefault("mma", {})
|
||||
mma_sec["epic"] = self.ui_epic_input
|
||||
mma_sec["tier_models"] = {t: {"model": d["model"], "provider": d.get("provider", "gemini")} for t, d in self.mma_tier_usage.items()}
|
||||
if self.active_track:
|
||||
mma_sec["active_track"] = asdict(self.active_track)
|
||||
else:
|
||||
@@ -1684,7 +1717,11 @@ class AppController:
|
||||
}
|
||||
self.config["ai"]["system_prompt"] = self.ui_global_system_prompt
|
||||
self.config["projects"] = {"paths": self.project_paths, "active": self.active_project_path}
|
||||
self.config["gui"] = {"show_windows": self.show_windows}
|
||||
self.config["gui"] = {
|
||||
"show_windows": self.show_windows,
|
||||
"separate_message_panel": getattr(self, "ui_separate_message_panel", False),
|
||||
"separate_response_panel": getattr(self, "ui_separate_response_panel", False),
|
||||
}
|
||||
theme.save_to_config(self.config)
|
||||
|
||||
def _do_generate(self) -> tuple[str, Path, list[dict[str, Any]], str, str]:
|
||||
|
||||
477
src/gui_2.py
477
src/gui_2.py
@@ -103,6 +103,13 @@ class App:
|
||||
self.node_editor_config = ed.Config()
|
||||
self.node_editor_ctx = ed.create_editor(self.node_editor_config)
|
||||
self.ui_selected_ticket_id: Optional[str] = None
|
||||
self._autofocus_response_tab = False
|
||||
gui_cfg = self.config.get("gui", {})
|
||||
self.ui_separate_message_panel = gui_cfg.get("separate_message_panel", False)
|
||||
self.ui_separate_response_panel = gui_cfg.get("separate_response_panel", False)
|
||||
self._comms_log_cache: list[dict[str, Any]] = []
|
||||
self._comms_log_dirty: bool = True
|
||||
self._last_ui_focus_agent: Optional[str] = None
|
||||
|
||||
def _handle_approve_tool(self, user_data=None) -> None:
|
||||
"""UI-level wrapper for approving a pending tool execution ask."""
|
||||
@@ -149,6 +156,11 @@ class App:
|
||||
|
||||
def shutdown(self) -> None:
|
||||
"""Cleanly shuts down the app's background tasks and saves state."""
|
||||
try:
|
||||
if hasattr(self, 'runner_params') and self.runner_params.ini_filename:
|
||||
imgui.save_ini_settings_to_disk(self.runner_params.ini_filename)
|
||||
except:
|
||||
pass
|
||||
self.controller.shutdown()
|
||||
|
||||
def _test_callback_func_write_to_file(self, data: str) -> None:
|
||||
@@ -226,6 +238,7 @@ class App:
|
||||
def _gui_func(self) -> None:
|
||||
try:
|
||||
self.perf_monitor.start_frame()
|
||||
self._autofocus_response_tab = self.controller._autofocus_response_tab
|
||||
# Process GUI task queue
|
||||
# DEBUG: Check if tasks exist before processing
|
||||
if hasattr(self, 'controller') and hasattr(self.controller, '_pending_gui_tasks'):
|
||||
@@ -249,11 +262,28 @@ class App:
|
||||
pass # silent — don't disrupt the GUI loop
|
||||
# Sync pending comms
|
||||
with self._pending_comms_lock:
|
||||
if self._pending_comms and self.ui_auto_scroll_comms:
|
||||
self._scroll_comms_to_bottom = True
|
||||
for c in self._pending_comms:
|
||||
self._comms_log.append(c)
|
||||
self._pending_comms.clear()
|
||||
if self._pending_comms:
|
||||
if self.ui_auto_scroll_comms:
|
||||
self._scroll_comms_to_bottom = True
|
||||
self._comms_log_dirty = True
|
||||
for c in self._pending_comms:
|
||||
self._comms_log.append(c)
|
||||
self._pending_comms.clear()
|
||||
|
||||
if self.ui_focus_agent != self._last_ui_focus_agent:
|
||||
self._comms_log_dirty = True
|
||||
self._last_ui_focus_agent = self.ui_focus_agent
|
||||
|
||||
if self._comms_log_dirty:
|
||||
if self.is_viewing_prior_session:
|
||||
self._comms_log_cache = self.prior_session_entries
|
||||
else:
|
||||
log_raw = list(self._comms_log)
|
||||
if self.ui_focus_agent:
|
||||
self._comms_log_cache = [e for e in log_raw if e.get("source_tier") == self.ui_focus_agent]
|
||||
else:
|
||||
self._comms_log_cache = log_raw
|
||||
self._comms_log_dirty = False
|
||||
with self._pending_tool_calls_lock:
|
||||
if self._pending_tool_calls and self.ui_auto_scroll_tool_calls:
|
||||
self._scroll_tool_calls_to_bottom = True
|
||||
@@ -281,10 +311,11 @@ class App:
|
||||
if exp:
|
||||
if imgui.collapsing_header("Provider & Model"):
|
||||
self._render_provider_panel()
|
||||
if imgui.collapsing_header("System Prompts"):
|
||||
self._render_system_prompts_panel()
|
||||
if imgui.collapsing_header("Token Budget"):
|
||||
self._render_token_budget_panel()
|
||||
if imgui.collapsing_header("System Prompts"):
|
||||
self._render_system_prompts_panel()
|
||||
|
||||
imgui.end()
|
||||
if self.show_windows.get("MMA Dashboard", False):
|
||||
exp, opened = imgui.begin("MMA Dashboard", self.show_windows["MMA Dashboard"])
|
||||
@@ -327,14 +358,39 @@ class App:
|
||||
self._render_discussion_panel()
|
||||
imgui.end_child()
|
||||
# Bottom part with tabs for message and response
|
||||
if imgui.begin_tab_bar("MessageResponseTabs"):
|
||||
if imgui.begin_tab_item("Message")[0]:
|
||||
self._render_message_panel()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item("Response")[0]:
|
||||
self._render_response_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
# Detach controls
|
||||
imgui.push_style_var(imgui.StyleVar_.item_spacing, imgui.ImVec2(10, 4))
|
||||
ch1, self.ui_separate_message_panel = imgui.checkbox("Pop Out Message", self.ui_separate_message_panel)
|
||||
imgui.same_line()
|
||||
ch2, self.ui_separate_response_panel = imgui.checkbox("Pop Out Response", self.ui_separate_response_panel)
|
||||
if ch1: self.show_windows["Message"] = self.ui_separate_message_panel
|
||||
if ch2: self.show_windows["Response"] = self.ui_separate_response_panel
|
||||
imgui.pop_style_var()
|
||||
|
||||
show_message_tab = not self.ui_separate_message_panel
|
||||
show_response_tab = not self.ui_separate_response_panel
|
||||
|
||||
if show_message_tab or show_response_tab:
|
||||
if imgui.begin_tab_bar("discussion_tabs"):
|
||||
# Task: Auto-focus Response tab when response received
|
||||
tab_flags = imgui.TabItemFlags_.none
|
||||
if self._autofocus_response_tab:
|
||||
tab_flags = imgui.TabItemFlags_.set_selected
|
||||
self._autofocus_response_tab = False
|
||||
self.controller._autofocus_response_tab = False
|
||||
|
||||
if show_message_tab:
|
||||
if imgui.begin_tab_item("Message", None)[0]:
|
||||
self._render_message_panel()
|
||||
imgui.end_tab_item()
|
||||
if show_response_tab:
|
||||
if imgui.begin_tab_item("Response", None, tab_flags)[0]:
|
||||
self._render_response_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
else:
|
||||
imgui.text_disabled("Message & Response panels are detached.")
|
||||
|
||||
imgui.end()
|
||||
if self.show_windows.get("Operations Hub", False):
|
||||
exp, opened = imgui.begin("Operations Hub", self.show_windows["Operations Hub"])
|
||||
@@ -354,16 +410,32 @@ class App:
|
||||
if self.ui_focus_agent:
|
||||
if imgui.button("x##clear_focus"):
|
||||
self.ui_focus_agent = None
|
||||
imgui.separator()
|
||||
if imgui.begin_tab_bar("OperationsTabs"):
|
||||
if imgui.begin_tab_item("Tool Calls")[0]:
|
||||
self._render_tool_calls_panel()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item("Comms History")[0]:
|
||||
self._render_comms_history_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
if exp:
|
||||
if imgui.begin_tab_bar("ops_tabs"):
|
||||
if imgui.begin_tab_item("Comms History")[0]:
|
||||
self._render_comms_history_panel()
|
||||
imgui.end_tab_item()
|
||||
if imgui.begin_tab_item("Tool Calls")[0]:
|
||||
self._render_tool_calls_panel()
|
||||
imgui.end_tab_item()
|
||||
imgui.end_tab_bar()
|
||||
|
||||
imgui.end()
|
||||
|
||||
if self.ui_separate_message_panel and self.show_windows.get("Message", False):
|
||||
exp, opened = imgui.begin("Message", self.show_windows["Message"])
|
||||
self.show_windows["Message"] = bool(opened)
|
||||
if exp:
|
||||
self._render_message_panel()
|
||||
imgui.end()
|
||||
|
||||
if self.ui_separate_response_panel and self.show_windows.get("Response", False):
|
||||
exp, opened = imgui.begin("Response", self.show_windows["Response"])
|
||||
self.show_windows["Response"] = bool(opened)
|
||||
if exp:
|
||||
self._render_response_panel()
|
||||
imgui.end()
|
||||
|
||||
if self.show_windows.get("Log Management", False):
|
||||
self._render_log_management()
|
||||
if self.show_windows["Diagnostics"]:
|
||||
@@ -729,11 +801,6 @@ class App:
|
||||
ch, val = imgui.checkbox(f"Enable {t_name}", val)
|
||||
if ch:
|
||||
self.ui_agent_tools[t_name] = val
|
||||
imgui.separator()
|
||||
imgui.text_colored(C_LBL, 'MMA Orchestration')
|
||||
_, self.ui_epic_input = imgui.input_text_multiline('##epic_input', self.ui_epic_input, imgui.ImVec2(-1, 80))
|
||||
if imgui.button('Plan Epic (Tier 1)', imgui.ImVec2(-1, 0)):
|
||||
self._cb_plan_epic()
|
||||
|
||||
def _render_track_proposal_modal(self) -> None:
|
||||
if self._show_track_proposal_modal:
|
||||
@@ -917,28 +984,32 @@ class App:
|
||||
self.prior_session_entries.clear()
|
||||
imgui.separator()
|
||||
imgui.begin_child("prior_scroll", imgui.ImVec2(0, 0), False)
|
||||
for idx, entry in enumerate(self.prior_session_entries):
|
||||
imgui.push_id(f"prior_{idx}")
|
||||
kind = entry.get("kind", entry.get("type", ""))
|
||||
imgui.text_colored(C_LBL, f"#{idx+1}")
|
||||
imgui.same_line()
|
||||
ts = entry.get("ts", entry.get("timestamp", ""))
|
||||
if ts:
|
||||
imgui.text_colored(vec4(160, 160, 160), str(ts))
|
||||
clipper = imgui.ListClipper()
|
||||
clipper.begin(len(self.prior_session_entries))
|
||||
while clipper.step():
|
||||
for idx in range(clipper.display_start, clipper.display_end):
|
||||
entry = self.prior_session_entries[idx]
|
||||
imgui.push_id(f"prior_{idx}")
|
||||
kind = entry.get("kind", entry.get("type", ""))
|
||||
imgui.text_colored(C_LBL, f"#{idx+1}")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_KEY, str(kind))
|
||||
payload = entry.get("payload", entry)
|
||||
text = payload.get("text", payload.get("message", payload.get("content", "")))
|
||||
if text:
|
||||
preview = str(text).replace("\\n", " ")[:200]
|
||||
if self.ui_word_wrap:
|
||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||
imgui.text(preview)
|
||||
imgui.pop_text_wrap_pos()
|
||||
else:
|
||||
imgui.text(preview)
|
||||
imgui.separator()
|
||||
imgui.pop_id()
|
||||
ts = entry.get("ts", entry.get("timestamp", ""))
|
||||
if ts:
|
||||
imgui.text_colored(vec4(160, 160, 160), str(ts))
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_KEY, str(kind))
|
||||
payload = entry.get("payload", entry)
|
||||
text = payload.get("text", payload.get("message", payload.get("content", "")))
|
||||
if text:
|
||||
preview = str(text).replace("\n", " ")[:200]
|
||||
if self.ui_word_wrap:
|
||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||
imgui.text(preview)
|
||||
imgui.pop_text_wrap_pos()
|
||||
else:
|
||||
imgui.text(preview)
|
||||
imgui.separator()
|
||||
imgui.pop_id()
|
||||
imgui.end_child()
|
||||
imgui.pop_style_color()
|
||||
return
|
||||
@@ -1000,7 +1071,7 @@ class App:
|
||||
if not self.is_viewing_prior_session:
|
||||
imgui.separator()
|
||||
if imgui.button("+ Entry"):
|
||||
self.disc_entries.append({"role": self.disc_roles[0] if self.disc_roles else "User", "content": "", "collapsed": False, "ts": project_manager.now_ts()})
|
||||
self.disc_entries.append({"role": self.disc_roles[0] if self.disc_roles else "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()})
|
||||
imgui.same_line()
|
||||
if imgui.button("-All"):
|
||||
for e in self.disc_entries: e["collapsed"] = True
|
||||
@@ -1076,7 +1147,7 @@ class App:
|
||||
if collapsed:
|
||||
imgui.same_line()
|
||||
if imgui.button("Ins"):
|
||||
self.disc_entries.insert(i, {"role": "User", "content": "", "collapsed": False, "ts": project_manager.now_ts()})
|
||||
self.disc_entries.insert(i, {"role": "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()})
|
||||
imgui.same_line()
|
||||
self._render_text_viewer(f"Entry #{i+1}", entry["content"])
|
||||
imgui.same_line()
|
||||
@@ -1147,8 +1218,9 @@ class App:
|
||||
if ch:
|
||||
if hasattr(ai_client, "_gemini_cli_adapter") and ai_client._gemini_cli_adapter:
|
||||
ai_client._gemini_cli_adapter.binary_path = self.ui_gemini_cli_path
|
||||
imgui.separator()
|
||||
imgui.text("Telemetry")
|
||||
|
||||
def _render_token_budget_panel(self) -> None:
|
||||
imgui.text("Session Telemetry")
|
||||
usage = self.session_usage
|
||||
total = usage["input_tokens"] + usage["output_tokens"]
|
||||
if total == 0 and usage.get("total_tokens", 0) > 0:
|
||||
@@ -1160,8 +1232,8 @@ class App:
|
||||
imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}")
|
||||
if self._gemini_cache_text:
|
||||
imgui.text_colored(C_SUB, self._gemini_cache_text)
|
||||
imgui.separator()
|
||||
|
||||
def _render_token_budget_panel(self) -> None:
|
||||
if self._token_stats_dirty:
|
||||
self._token_stats_dirty = False
|
||||
self._refresh_api_metrics({}, md_content=self._last_stable_md or None)
|
||||
@@ -1316,6 +1388,7 @@ class App:
|
||||
if imgui.button("Exit Prior Session"):
|
||||
self.is_viewing_prior_session = False
|
||||
self.prior_session_entries.clear()
|
||||
self._comms_log_dirty = True
|
||||
self.ai_status = "idle"
|
||||
imgui.separator()
|
||||
imgui.text_colored(vec4(255, 200, 100), "VIEWING PRIOR SESSION")
|
||||
@@ -1334,62 +1407,77 @@ class App:
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_TR, "tool_result")
|
||||
imgui.separator()
|
||||
|
||||
# Use tinted background for prior session
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 30, 20))
|
||||
|
||||
imgui.begin_child("comms_scroll", imgui.ImVec2(0, 0), False, imgui.WindowFlags_.horizontal_scrollbar)
|
||||
log_to_render = self.prior_session_entries if self.is_viewing_prior_session else list(self._comms_log)
|
||||
if self.ui_focus_agent and not self.is_viewing_prior_session:
|
||||
log_to_render = [e for e in log_to_render if e.get("source_tier") == self.ui_focus_agent]
|
||||
clipper = imgui.ListClipper()
|
||||
clipper.begin(len(log_to_render))
|
||||
while clipper.step():
|
||||
for i_minus_one in range(clipper.display_start, clipper.display_end):
|
||||
i = i_minus_one + 1
|
||||
entry = log_to_render[i_minus_one]
|
||||
local_ts = entry.get("local_ts", 0)
|
||||
blink_alpha = 0.0
|
||||
if entry.get("_blinking", False):
|
||||
elapsed = time.time() - entry.get("_blink_start", 0)
|
||||
if elapsed < 1.5:
|
||||
blink_alpha = 0.3 + 0.7 * abs(math.sin(elapsed * 8 * math.pi))
|
||||
|
||||
log_to_render = self._comms_log_cache
|
||||
|
||||
flags = imgui.TableFlags_.resizable | imgui.TableFlags_.hideable | imgui.TableFlags_.borders_inner_v | imgui.TableFlags_.row_bg | imgui.TableFlags_.scroll_y
|
||||
|
||||
if imgui.begin_table("comms_table", 5, flags):
|
||||
imgui.table_setup_column("#", imgui.TableColumnFlags_.width_fixed, 40)
|
||||
imgui.table_setup_column("Tier", imgui.TableColumnFlags_.width_fixed, 60)
|
||||
imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 80)
|
||||
imgui.table_setup_column("!", imgui.TableColumnFlags_.width_fixed, 20)
|
||||
imgui.table_setup_column("Content", imgui.TableColumnFlags_.width_stretch)
|
||||
|
||||
clipper = imgui.ListClipper()
|
||||
clipper.begin(len(log_to_render))
|
||||
while clipper.step():
|
||||
for i in range(clipper.display_start, clipper.display_end):
|
||||
entry = log_to_render[i]
|
||||
imgui.table_next_row()
|
||||
|
||||
i_display = i + 1
|
||||
source = entry.get("source_tier", "main")
|
||||
msg_type = entry.get("type", "?")
|
||||
content_text = entry.get("content", "")
|
||||
if len(content_text) > COMMS_CLAMP_CHARS:
|
||||
content_text = content_text[:COMMS_CLAMP_CHARS] + "..."
|
||||
|
||||
# FG Color based on type
|
||||
fg = C_VAL
|
||||
if msg_type == "request": fg = C_REQ
|
||||
elif msg_type == "response": fg = C_RES
|
||||
elif msg_type == "tool_call": fg = C_TC
|
||||
elif msg_type == "tool_result": fg = C_TR
|
||||
elif msg_type == "error": fg = vec4(255, 80, 80)
|
||||
|
||||
imgui.table_next_column()
|
||||
imgui.text_colored(C_LBL, f"#{i_display}")
|
||||
|
||||
imgui.table_next_column()
|
||||
imgui.text_colored(C_SUB, f"[{source}]")
|
||||
|
||||
imgui.table_next_column()
|
||||
imgui.text_colored(fg, msg_type)
|
||||
|
||||
imgui.table_next_column()
|
||||
elapsed = time.time() - entry.get("local_ts", 0)
|
||||
if elapsed < 3.0:
|
||||
blink = (math.sin(elapsed * 15) * 0.5 + 0.5)
|
||||
imgui.text_colored(vec4(255, 255, 0, blink), "*")
|
||||
else:
|
||||
entry["_blinking"] = False
|
||||
source = entry.get("source_tier", "?")
|
||||
msg_type = entry.get("type", "?")
|
||||
content_text = entry.get("content", "")
|
||||
if len(content_text) > COMMS_CLAMP_CHARS:
|
||||
content_text = content_text[:COMMS_CLAMP_CHARS] + "..."
|
||||
if msg_type == "request":
|
||||
bg = vec4(60, 40, 20, 180)
|
||||
fg = C_REQ
|
||||
elif msg_type == "response":
|
||||
bg = vec4(20, 60, 40, 180)
|
||||
fg = C_RES
|
||||
elif msg_type == "tool_call":
|
||||
bg = vec4(40, 40, 80, 180)
|
||||
fg = C_TC
|
||||
elif msg_type == "tool_result":
|
||||
bg = vec4(80, 40, 40, 180)
|
||||
fg = C_TR
|
||||
elif msg_type == "error":
|
||||
bg = vec4(80, 20, 20, 180)
|
||||
fg = vec4(1, 0.3, 0.3, 1)
|
||||
else:
|
||||
bg = vec4(50, 50, 50, 180)
|
||||
fg = C_OUT if source == "AI" else C_IN
|
||||
imgui.push_style_color(imgui.Col_.child_bg, bg)
|
||||
imgui.push_style_color(imgui.Col_.text, fg)
|
||||
imgui.text_colored(C_KEY, f"#{i}")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_LBL, f"[{source}]")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_LBL, msg_type)
|
||||
if blink_alpha > 0:
|
||||
imgui.same_line()
|
||||
imgui.text_colored(vec4(1, 1, 0, blink_alpha), " ●")
|
||||
imgui.same_line()
|
||||
imgui.text_wrapped(content_text)
|
||||
imgui.pop_style_color(2)
|
||||
imgui.text("")
|
||||
|
||||
imgui.table_next_column()
|
||||
if self.ui_word_wrap:
|
||||
imgui.push_text_wrap_pos(0.0)
|
||||
imgui.text_unformatted(content_text)
|
||||
imgui.pop_text_wrap_pos()
|
||||
else:
|
||||
imgui.text_unformatted(content_text)
|
||||
|
||||
imgui.end_table()
|
||||
|
||||
if self._scroll_comms_to_bottom:
|
||||
imgui.set_scroll_here_y(1.0)
|
||||
self._scroll_comms_to_bottom = False
|
||||
|
||||
imgui.end_child()
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.pop_style_color()
|
||||
@@ -1482,6 +1570,13 @@ class App:
|
||||
elif self.mma_status == "done": status_col = imgui.ImVec4(0, 1, 0, 1)
|
||||
elif self.mma_status == "error": status_col = imgui.ImVec4(1, 0, 0, 1)
|
||||
imgui.text_colored(status_col, self.mma_status.upper())
|
||||
|
||||
imgui.separator()
|
||||
imgui.text_colored(C_LBL, 'Epic Planning (Tier 1)')
|
||||
_, self.ui_epic_input = imgui.input_text_multiline('##epic_input', self.ui_epic_input, imgui.ImVec2(-1, 80))
|
||||
if imgui.button('Plan Epic (Tier 1)', imgui.ImVec2(-1, 0)):
|
||||
self._cb_plan_epic()
|
||||
|
||||
imgui.separator()
|
||||
# 0. Conductor Setup
|
||||
if imgui.collapsing_header("Conductor Setup"):
|
||||
@@ -1631,12 +1726,36 @@ class App:
|
||||
imgui.text(f"{tier}:")
|
||||
imgui.same_line()
|
||||
current_model = self.mma_tier_usage[tier].get("model", "unknown")
|
||||
if imgui.begin_combo(f"##combo_{tier}", current_model):
|
||||
for model in self.available_models:
|
||||
current_provider = self.mma_tier_usage[tier].get("provider", "gemini")
|
||||
|
||||
imgui.push_id(f"tier_cfg_{tier}")
|
||||
|
||||
# Provider selection
|
||||
imgui.push_item_width(100)
|
||||
if imgui.begin_combo("##prov", current_provider):
|
||||
for p in PROVIDERS:
|
||||
if imgui.selectable(p, p == current_provider)[0]:
|
||||
self.mma_tier_usage[tier]["provider"] = p
|
||||
# Reset model to default for provider
|
||||
models_list = self.controller.all_available_models.get(p, [])
|
||||
if models_list:
|
||||
self.mma_tier_usage[tier]["model"] = models_list[0]
|
||||
imgui.end_combo()
|
||||
imgui.pop_item_width()
|
||||
|
||||
imgui.same_line()
|
||||
|
||||
# Model selection
|
||||
imgui.push_item_width(-1)
|
||||
models_list = self.controller.all_available_models.get(current_provider, [])
|
||||
if imgui.begin_combo("##model", current_model):
|
||||
for model in models_list:
|
||||
if imgui.selectable(model, current_model == model)[0]:
|
||||
self.mma_tier_usage[tier]["model"] = model
|
||||
self.project.setdefault("mma", {}).setdefault("tier_models", {})[tier] = model
|
||||
imgui.end_combo()
|
||||
imgui.pop_item_width()
|
||||
|
||||
imgui.pop_id()
|
||||
imgui.separator()
|
||||
# 4. Task DAG Visualizer
|
||||
imgui.text("Task DAG")
|
||||
@@ -1820,137 +1939,6 @@ class App:
|
||||
pass
|
||||
imgui.end_child()
|
||||
|
||||
imgui.text_colored(vec4(200, 220, 160), f"Status: {self.ai_status}")
|
||||
imgui.same_line()
|
||||
if imgui.button("Clear##comms"):
|
||||
ai_client.clear_comms_log()
|
||||
self._comms_log.clear()
|
||||
imgui.same_line()
|
||||
if imgui.button("Load Log"):
|
||||
self.cb_load_prior_log()
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.same_line()
|
||||
if imgui.button("Exit Prior Session"):
|
||||
self.is_viewing_prior_session = False
|
||||
self.prior_session_entries.clear()
|
||||
self.ai_status = "idle"
|
||||
imgui.separator()
|
||||
imgui.text_colored(vec4(255, 200, 100), "VIEWING PRIOR SESSION")
|
||||
imgui.separator()
|
||||
imgui.text_colored(C_OUT, "OUT")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_REQ, "request")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_TC, "tool_call")
|
||||
imgui.same_line()
|
||||
imgui.text(" ")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_IN, "IN")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_RES, "response")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_TR, "tool_result")
|
||||
imgui.separator()
|
||||
# Use tinted background for prior session
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 30, 20))
|
||||
imgui.begin_child("comms_scroll", imgui.ImVec2(0, 0), False, imgui.WindowFlags_.horizontal_scrollbar)
|
||||
log_to_render = self.prior_session_entries if self.is_viewing_prior_session else list(self._comms_log)
|
||||
if self.ui_focus_agent and not self.is_viewing_prior_session:
|
||||
log_to_render = [e for e in log_to_render if e.get("source_tier") == self.ui_focus_agent]
|
||||
for idx_minus_one, entry in enumerate(log_to_render):
|
||||
idx = idx_minus_one + 1
|
||||
local_ts = entry.get("local_ts", 0)
|
||||
# Blink effect
|
||||
blink_alpha = 0.0
|
||||
if local_ts > 0 and not self.is_viewing_prior_session:
|
||||
elapsed = time.time() - local_ts
|
||||
if elapsed < 3.0:
|
||||
blink_alpha = (1.0 - (elapsed / 3.0)) * 0.3 * (math.sin(elapsed * 10) * 0.5 + 0.5)
|
||||
imgui.push_id(f"comms_{idx}")
|
||||
if blink_alpha > 0:
|
||||
# Draw a background highlight for the entry
|
||||
imgui.get_window_draw_list()
|
||||
imgui.get_cursor_screen_pos()
|
||||
# Estimate height or just use a fixed height for the background
|
||||
# It's better to wrap the entry in a group or just use separators
|
||||
# For now, let's just use the style color push if we are sure we pop it
|
||||
imgui.push_style_color(imgui.Col_.child_bg, vec4(0, 255, 0, blink_alpha))
|
||||
# We still need a child or a group to apply the background to
|
||||
imgui.begin_group()
|
||||
d = entry.get("direction", "IN")
|
||||
k = entry.get("kind", "response")
|
||||
imgui.text_colored(vec4(160, 160, 160), f"#{idx}")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(vec4(160, 160, 160), entry.get("ts", "00:00:00"))
|
||||
imgui.same_line()
|
||||
imgui.text_colored(DIR_COLORS.get(d, C_VAL), d)
|
||||
imgui.same_line()
|
||||
imgui.text_colored(KIND_COLORS.get(k, C_VAL), k)
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_LBL, f"{entry.get('provider', '?')}/{entry.get('model', '?')}")
|
||||
imgui.same_line()
|
||||
tier_label = entry.get("source_tier") or "main"
|
||||
imgui.text_colored(C_SUB, f"[{tier_label}]")
|
||||
payload = entry.get("payload", {})
|
||||
if k == "request":
|
||||
self._render_heavy_text("message", payload.get("message", ""))
|
||||
elif k == "response":
|
||||
imgui.text_colored(C_LBL, "round:")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_VAL, str(payload.get("round", "")))
|
||||
imgui.text_colored(C_LBL, "stop_reason:")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(vec4(255, 200, 120), str(payload.get("stop_reason", "")))
|
||||
text = payload.get("text", "")
|
||||
if text: self._render_heavy_text("text", text)
|
||||
imgui.text_colored(C_LBL, "tool_calls:")
|
||||
tcs = payload.get("tool_calls", [])
|
||||
if not tcs: imgui.text_colored(C_VAL, " (none)")
|
||||
for tc_i, tc in enumerate(tcs):
|
||||
imgui.text_colored(C_KEY, f" call[{tc_i}] {tc.get('name', '?')}")
|
||||
if tc.get("id"):
|
||||
imgui.text_colored(C_LBL, " id:")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_VAL, str(tc["id"]))
|
||||
if "args" in tc or "input" in tc:
|
||||
self._render_heavy_text(f"call_{tc_i}_args", str(tc.get("args") or tc.get("input")))
|
||||
elif k == "tool_call":
|
||||
imgui.text_colored(C_KEY, payload.get("name", "?"))
|
||||
if payload.get("id"):
|
||||
imgui.text_colored(C_LBL, " id:")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_VAL, str(payload["id"]))
|
||||
if "script" in payload: self._render_heavy_text("script", payload["script"])
|
||||
if "args" in payload: self._render_heavy_text("args", str(payload["args"]))
|
||||
elif k == "tool_result":
|
||||
imgui.text_colored(C_KEY, payload.get("name", "?"))
|
||||
if payload.get("id"):
|
||||
imgui.text_colored(C_LBL, " id:")
|
||||
imgui.same_line()
|
||||
imgui.text_colored(C_VAL, str(payload["id"]))
|
||||
if "output" in payload: self._render_heavy_text("output", payload["output"])
|
||||
if "results" in payload:
|
||||
for r_i, r in enumerate(payload["results"]):
|
||||
imgui.text_colored(C_LBL, f" Result[{r_i}]:")
|
||||
self._render_heavy_text(f"res_{r_i}", str(r))
|
||||
if "usage" in payload:
|
||||
u = payload["usage"]
|
||||
u_str = f"In: {u.get('input_tokens', 0)} Out: {u.get('output_tokens', 0)}"
|
||||
if u.get("cache_read_input_tokens"): u_str += f" (Cache: {u['cache_read_input_tokens']})"
|
||||
imgui.text_colored(C_SUB, f" Usage: {u_str}")
|
||||
imgui.separator()
|
||||
if blink_alpha > 0:
|
||||
imgui.end_group()
|
||||
imgui.pop_style_color()
|
||||
imgui.pop_id()
|
||||
if self._scroll_comms_to_bottom:
|
||||
imgui.set_scroll_here_y(1.0)
|
||||
self._scroll_comms_to_bottom = False
|
||||
imgui.end_child()
|
||||
if self.is_viewing_prior_session:
|
||||
imgui.pop_style_color()
|
||||
|
||||
def _render_system_prompts_panel(self) -> None:
|
||||
imgui.text("Global System Prompt (all projects)")
|
||||
ch, self.ui_global_system_prompt = imgui.input_text_multiline("##gsp", self.ui_global_system_prompt, imgui.ImVec2(-1, 100))
|
||||
@@ -1969,6 +1957,13 @@ class App:
|
||||
if imgui.selectable(p, p == cp)[0]:
|
||||
theme.apply(p)
|
||||
imgui.end_combo()
|
||||
|
||||
imgui.separator()
|
||||
ch1, self.ui_separate_message_panel = imgui.checkbox("Separate Message Panel", self.ui_separate_message_panel)
|
||||
ch2, self.ui_separate_response_panel = imgui.checkbox("Separate Response Panel", self.ui_separate_response_panel)
|
||||
if ch1: self.show_windows["Message"] = self.ui_separate_message_panel
|
||||
if ch2: self.show_windows["Response"] = self.ui_separate_response_panel
|
||||
|
||||
imgui.separator()
|
||||
imgui.text("Font")
|
||||
imgui.push_item_width(-150)
|
||||
|
||||
@@ -57,7 +57,7 @@ def parse_history_entries(history_strings: list[str], roles: list[str]) -> list[
|
||||
content = rest[match.end():].strip()
|
||||
else:
|
||||
content = rest
|
||||
entries.append({"role": role, "content": content, "collapsed": False, "ts": ts})
|
||||
entries.append({"role": role, "content": content, "collapsed": True, "ts": ts})
|
||||
return entries
|
||||
|
||||
@dataclass
|
||||
|
||||
Reference in New Issue
Block a user