some organization pass, still need to review a bunch

This commit is contained in:
ed
2026-06-06 00:21:36 -04:00
parent f8b0a1243d
commit 053f5d867a
18 changed files with 658 additions and 706 deletions
+1 -1
View File
@@ -4170,7 +4170,7 @@ def render_operations_hub(app: App) -> None:
with imscope.tab_item("Vendor State") as (exp, _): with imscope.tab_item("Vendor State") as (exp, _):
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: # TODO(Ed): Shouldn't this just be a part of usage analytics? We can show all used vendors at once...
"""Render the Operations Hub > Vendor State panel. """Render the Operations Hub > Vendor State panel.
[C: src/vendor_state.py:get_vendor_state] [C: src/vendor_state.py:get_vendor_state]
""" """
-2
View File
@@ -35,7 +35,6 @@ def parse_ts(s: str) -> Optional[datetime.datetime]:
def entry_to_str(entry: dict[str, Any]) -> str: def entry_to_str(entry: dict[str, Any]) -> str:
""" """
Serialise a disc entry dict -> stored string. Serialise a disc entry dict -> stored string.
[C: tests/test_thinking_persistence.py:test_entry_to_str_with_thinking] [C: tests/test_thinking_persistence.py:test_entry_to_str_with_thinking]
""" """
@@ -62,7 +61,6 @@ def format_discussion(entries: list[dict[str, Any]]) -> str:
def str_to_entry(raw: str, roles: list[str]) -> dict[str, Any]: def str_to_entry(raw: str, roles: list[str]) -> dict[str, Any]:
""" """
Parse a stored string back to a disc entry dict. Parse a stored string back to a disc entry dict.
[C: tests/test_thinking_persistence.py:test_str_to_entry_with_thinking] [C: tests/test_thinking_persistence.py:test_str_to_entry_with_thinking]
""" """
+8 -10
View File
@@ -6,9 +6,13 @@ import sys
from typing import List, Dict, Any, Optional from typing import List, Dict, Any, Optional
from src import ai_client
from src import models from src import models
from src import mcp_client from src import mcp_client
from src.file_cache import ASTParser
_SENTENCE_TRANSFORMERS = None _SENTENCE_TRANSFORMERS = None
_GOOGLE_GENAI = None _GOOGLE_GENAI = None
_CHROMADB = None _CHROMADB = None
@@ -74,7 +78,6 @@ class GeminiEmbeddingProvider(BaseEmbeddingProvider):
if google_module is None: if google_module is None:
raise ImportError("google-genai is not installed") raise ImportError("google-genai is not installed")
genai_pkg, types = google_module genai_pkg, types = google_module
from src import ai_client
ai_client._ensure_gemini_client() ai_client._ensure_gemini_client()
client = ai_client._gemini_client client = ai_client._gemini_client
if not client: if not client:
@@ -94,8 +97,7 @@ class RAGEngine:
self.collection = None self.collection = None
self.embedding_provider = None self.embedding_provider = None
if not self.config.enabled: if not self.config.enabled: return
return
self._init_embedding_provider() self._init_embedding_provider()
self._init_vector_store() self._init_vector_store()
@@ -168,7 +170,6 @@ class RAGEngine:
def _chunk_code(self, content: str, file_path: str) -> List[str]: def _chunk_code(self, content: str, file_path: str) -> List[str]:
"""AST-aware chunking for Python code.""" """AST-aware chunking for Python code."""
try: try:
from src.file_cache import ASTParser
parser = ASTParser("python") parser = ASTParser("python")
tree = parser.parse(content) tree = parser.parse(content)
chunks = [] chunks = []
@@ -246,12 +247,9 @@ class RAGEngine:
""" """
[C: tests/mock_concurrent_mma.py:main, tests/test_rag_engine.py:test_rag_engine_chroma] [C: tests/mock_concurrent_mma.py:main, tests/test_rag_engine.py:test_rag_engine_chroma]
""" """
if not self.config.enabled: if not self.config.enabled: return []
return [] if self.config.vector_store.provider == 'mcp': return self._search_mcp(query, top_k)
if self.config.vector_store.provider == 'mcp': if self.collection == "mock": return []
return self._search_mcp(query, top_k)
if self.collection == "mock":
return []
query_embedding = self.embedding_provider.embed([query])[0] query_embedding = self.embedding_provider.embed([query])[0]
results = self.collection.query( results = self.collection.query(
-1
View File
@@ -90,7 +90,6 @@ def open_session(label: Optional[str] = None) -> None:
def close_session() -> None: def close_session() -> None:
""" """
Flush and close all log files. Called on clean exit. Flush and close all log files. Called on clean exit.
[C: tests/test_app_controller_offloading.py:tmp_session_dir, tests/test_logging_e2e.py:e2e_setup, tests/test_logging_e2e.py:test_logging_e2e, tests/test_session_logger_optimization.py:temp_session_setup, tests/test_session_logger_reset.py:temp_logs, tests/test_session_logging.py:temp_logs] [C: tests/test_app_controller_offloading.py:tmp_session_dir, tests/test_logging_e2e.py:e2e_setup, tests/test_logging_e2e.py:test_logging_e2e, tests/test_session_logger_optimization.py:temp_session_setup, tests/test_session_logger_reset.py:temp_logs, tests/test_session_logging.py:temp_logs]
""" """
+1 -4
View File
@@ -8,8 +8,7 @@ def draw_soft_shadow(draw_list: imgui.ImDrawList, p_min: imgui.ImVec2, p_max: im
""" """
r, g, b, a = color.x, color.y, color.z, color.w r, g, b, a = color.x, color.y, color.z, color.w
steps = int(shadow_size) steps = int(shadow_size)
if steps <= 0: if steps <= 0: return
return
alpha_step = a / steps alpha_step = a / steps
@@ -17,12 +16,10 @@ def draw_soft_shadow(draw_list: imgui.ImDrawList, p_min: imgui.ImVec2, p_max: im
current_alpha = a - (i * alpha_step) current_alpha = a - (i * alpha_step)
# Apply an easing function (e.g., cubic) for a smoother shadow falloff # Apply an easing function (e.g., cubic) for a smoother shadow falloff
current_alpha = current_alpha * (1.0 - (i / steps)**2) current_alpha = current_alpha * (1.0 - (i / steps)**2)
if current_alpha <= 0.01: if current_alpha <= 0.01:
continue continue
expand = float(i) expand = float(i)
c_min = imgui.ImVec2(p_min.x - expand, p_min.y - expand) c_min = imgui.ImVec2(p_min.x - expand, p_min.y - expand)
c_max = imgui.ImVec2(p_max.x + expand, p_max.y + expand) c_max = imgui.ImVec2(p_max.x + expand, p_max.y + expand)
+6 -22
View File
@@ -1,16 +1,5 @@
# summarize.py # summarize.py
""" """
Note(Gemini):
Local heuristic summariser. Doesn't use any AI or network.
Uses Python's AST to reliably pull out classes, methods, and functions.
Regex is used for TOML and Markdown.
The rationale here is simple: giving the AI the *structure* of a codebase is 90%
as good as giving it the full source, but costs 1% of the tokens.
If it needs the full source of a file after reading the summary, it can just call read_file.
"""
# summarize.py
"""
Local symbolic summariser — no AI calls, no network. Local symbolic summariser — no AI calls, no network.
For each file, extracts structural information: For each file, extracts structural information:
@@ -28,6 +17,8 @@ import re
from pathlib import Path from pathlib import Path
from typing import Callable, Any from typing import Callable, Any
from src import ai_client
from src.summary_cache import SummaryCache, get_file_hash from src.summary_cache import SummaryCache, get_file_hash
@@ -73,16 +64,13 @@ def _summarise_python(path: Path, content: str) -> str:
n.name for n in ast.iter_child_nodes(node) n.name for n in ast.iter_child_nodes(node)
if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))
] ]
if methods: if methods: parts.append(f"class {node.name}: {', '.join(methods)}")
parts.append(f"class {node.name}: {', '.join(methods)}") else: parts.append(f"class {node.name}")
else:
parts.append(f"class {node.name}")
top_fns = [ top_fns = [
node.name for node in ast.iter_child_nodes(tree) node.name for node in ast.iter_child_nodes(tree)
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
] ]
if top_fns: if top_fns: parts.append(f"functions: {', '.join(top_fns)}")
parts.append(f"functions: {', '.join(top_fns)}")
return "\n".join(parts) return "\n".join(parts)
def _summarise_toml(path: Path, content: str) -> str: def _summarise_toml(path: Path, content: str) -> str:
@@ -168,16 +156,13 @@ _SUMMARISERS: dict[str, Callable[[Path, str], str]] = {
def summarise_file(path: Path, content: str) -> str: def summarise_file(path: Path, content: str) -> str:
""" """
Return a compact markdown summary string for a single file. Return a compact markdown summary string for a single file.
`content` is the already-read file text (or an error string). `content` is the already-read file text (or an error string).
[C: tests/test_subagent_summarization.py:test_summarise_file_integration] [C: tests/test_subagent_summarization.py:test_summarise_file_integration]
""" """
content_hash = get_file_hash(content) content_hash = get_file_hash(content)
cached = _summary_cache.get_summary(str(path), content_hash) cached = _summary_cache.get_summary(str(path), content_hash)
if cached: if cached: return cached
return cached
suffix = path.suffix.lower() if hasattr(path, "suffix") else "" suffix = path.suffix.lower() if hasattr(path, "suffix") else ""
fn = _SUMMARISERS.get(suffix, _summarise_generic) fn = _SUMMARISERS.get(suffix, _summarise_generic)
try: try:
@@ -185,7 +170,6 @@ def summarise_file(path: Path, content: str) -> str:
# Smart AI Summarization # Smart AI Summarization
is_code = suffix in [".py", ".ps1", ".js", ".ts", ".cpp", ".c", ".h", ".cs", ".go", ".rs", ".lua"] is_code = suffix in [".py", ".ps1", ".js", ".ts", ".cpp", ".c", ".h", ".cs", ".go", ".rs", ".lua"]
try: try:
from src import ai_client
smart_summary = ai_client.run_subagent_summarization( smart_summary = ai_client.run_subagent_summarization(
file_path=str(path), file_path=str(path),
content=content[:10000], content=content[:10000],
-7
View File
@@ -7,7 +7,6 @@ from typing import Optional, Dict
def get_file_hash(content: str) -> str: def get_file_hash(content: str) -> str:
""" """
Returns SHA256 hash of the content. Returns SHA256 hash of the content.
[C: tests/test_summary_cache.py:test_get_file_hash, tests/test_summary_cache.py:test_summary_cache] [C: tests/test_summary_cache.py:test_get_file_hash, tests/test_summary_cache.py:test_summary_cache]
""" """
@@ -15,8 +14,6 @@ def get_file_hash(content: str) -> str:
class SummaryCache: class SummaryCache:
""" """
A hash-based cache for file summaries to avoid redundant processing. A hash-based cache for file summaries to avoid redundant processing.
Invalidates when content hash changes. Invalidates when content hash changes.
""" """
@@ -32,7 +29,6 @@ class SummaryCache:
def load(self) -> None: def load(self) -> None:
""" """
Loads cache from disk. Loads cache from disk.
[C: src/tool_presets.py:ToolPresetManager._read_raw, src/workspace_manager.py:WorkspaceManager._load_file, tests/test_gui_phase3.py:test_create_track, tests/test_history_management.py:test_save_separation, tests/test_session_logging.py:test_open_session_creates_subdir_and_registry] [C: src/tool_presets.py:ToolPresetManager._read_raw, src/workspace_manager.py:WorkspaceManager._load_file, tests/test_gui_phase3.py:test_create_track, tests/test_history_management.py:test_save_separation, tests/test_session_logging.py:test_open_session_creates_subdir_and_registry]
""" """
@@ -54,7 +50,6 @@ class SummaryCache:
def get_summary(self, file_path: str, content_hash: str) -> Optional[str]: def get_summary(self, file_path: str, content_hash: str) -> Optional[str]:
""" """
Returns cached summary if hash matches, otherwise None. Returns cached summary if hash matches, otherwise None.
[C: tests/test_summary_cache.py:test_summary_cache, tests/test_summary_cache.py:test_summary_cache_lru] [C: tests/test_summary_cache.py:test_summary_cache, tests/test_summary_cache.py:test_summary_cache_lru]
""" """
@@ -68,7 +63,6 @@ class SummaryCache:
def set_summary(self, file_path: str, content_hash: str, summary: str) -> None: def set_summary(self, file_path: str, content_hash: str, summary: str) -> None:
""" """
Stores summary in cache and saves to disk. Stores summary in cache and saves to disk.
[C: tests/test_summary_cache.py:test_summary_cache, tests/test_summary_cache.py:test_summary_cache_lru] [C: tests/test_summary_cache.py:test_summary_cache, tests/test_summary_cache.py:test_summary_cache_lru]
""" """
@@ -87,7 +81,6 @@ class SummaryCache:
def clear(self) -> None: def clear(self) -> None:
""" """
Clears the cache both in-memory and on disk. Clears the cache both in-memory and on disk.
[C: tests/conftest.py:reset_ai_client] [C: tests/conftest.py:reset_ai_client]
""" """
+1 -2
View File
@@ -14,7 +14,7 @@ from contextlib import nullcontext
from imgui_bundle import imgui, hello_imgui from imgui_bundle import imgui, hello_imgui
from typing import Any, Optional from typing import Any, Optional
import src.theme_nerv from src import theme_nerv
from src import imgui_scopes as imscope from src import imgui_scopes as imscope
from src.theme_nerv import DATA_GREEN from src.theme_nerv import DATA_GREEN
@@ -213,7 +213,6 @@ def apply(palette_name: str) -> None:
global _current_palette global _current_palette
_current_palette = palette_name _current_palette = palette_name
if palette_name == 'NERV': if palette_name == 'NERV':
from src import theme_nerv
theme_nerv.apply_nerv() theme_nerv.apply_nerv()
apply_syntax_palette(get_syntax_palette_for_theme(palette_name)) apply_syntax_palette(get_syntax_palette_for_theme(palette_name))
return return
+6 -6
View File
@@ -204,14 +204,14 @@ def load_themes_from_toml(path: Path, scope: str) -> dict[str, ThemeFile]:
except Exception as e: except Exception as e:
print(f"warning: failed to parse {path}: {e}", file=sys.stderr) print(f"warning: failed to parse {path}: {e}", file=sys.stderr)
return out return out
if not isinstance(data, dict):
return out if not isinstance(data, dict): return out
themes_sec = data.get("themes", {}) themes_sec = data.get("themes", {})
if not isinstance(themes_sec, dict): if not isinstance(themes_sec, dict): return out
return out
for name, theme_data in themes_sec.items(): for name, theme_data in themes_sec.items():
if not isinstance(theme_data, dict): if not isinstance(theme_data, dict): continue
continue
try: try:
theme = ThemeFile.from_dict(name, theme_data, source_path=path, scope=scope) theme = ThemeFile.from_dict(name, theme_data, source_path=path, scope=scope)
except ValueError as e: except ValueError as e:
-1
View File
@@ -64,7 +64,6 @@ NERV_PALETTE = {
def apply_nerv() -> None: def apply_nerv() -> None:
""" """
Apply NERV theme with hard edges and specific palette. Apply NERV theme with hard edges and specific palette.
[C: tests/test_theme_nerv.py:test_apply_nerv_sets_rounding_and_colors] [C: tests/test_theme_nerv.py:test_apply_nerv_sets_rounding_and_colors]
""" """
+1 -3
View File
@@ -13,8 +13,7 @@ class CRTFilter:
""" """
[C: tests/test_theme_nerv_alert.py:test_alert_pulsing_render_active, tests/test_theme_nerv_alert.py:test_alert_pulsing_render_inactive, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_alert_pulsing_render, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_disabled, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_render] [C: tests/test_theme_nerv_alert.py:test_alert_pulsing_render_active, tests/test_theme_nerv_alert.py:test_alert_pulsing_render_inactive, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_alert_pulsing_render, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_disabled, tests/test_theme_nerv_fx.py:TestThemeNervFx.test_crt_filter_render]
""" """
if not self.enabled: if not self.enabled: return
return
draw_list = imgui.get_foreground_draw_list() draw_list = imgui.get_foreground_draw_list()
# 1. Enhanced Scanlines (Horizontal) # 1. Enhanced Scanlines (Horizontal)
@@ -40,7 +39,6 @@ class CRTFilter:
# Exponential alpha for smoother falloff # Exponential alpha for smoother falloff
alpha = (i / v_steps) ** 3.0 * 0.25 alpha = (i / v_steps) ** 3.0 * 0.25
v_color = imgui.get_color_u32((0.0, 0.0, 0.0, alpha)) v_color = imgui.get_color_u32((0.0, 0.0, 0.0, alpha))
# Inset and rounding grow to simulate tube curvature # Inset and rounding grow to simulate tube curvature
inset = (v_steps - i) * 4.5 inset = (v_steps - i) * 4.5
rounding = 60.0 + (v_steps - i) * 8.0 rounding = 60.0 + (v_steps - i) * 8.0
+1 -6
View File
@@ -7,8 +7,6 @@ from src.models import ThinkingSegment
def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]: def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
""" """
Parses thinking segments from text and returns (segments, response_content). Parses thinking segments from text and returns (segments, response_content).
Support extraction of thinking traces from <thinking>...</thinking>, <thought>...</thought>, Support extraction of thinking traces from <thinking>...</thinking>, <thought>...</thought>,
and blocks prefixed with Thinking:. and blocks prefixed with Thinking:.
@@ -18,7 +16,6 @@ def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
# 1. Extract <thinking> and <thought> tags # 1. Extract <thinking> and <thought> tags
current_text = text current_text = text
# Combined pattern for tags # Combined pattern for tags
tag_pattern = re.compile(r'<(thinking|thought)>(.*?)</\1>', re.DOTALL | re.IGNORECASE) tag_pattern = re.compile(r'<(thinking|thought)>(.*?)</\1>', re.DOTALL | re.IGNORECASE)
@@ -46,8 +43,7 @@ def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
def replace_func(match): def replace_func(match):
content = match.group(1).strip() content = match.group(1).strip()
if content: if content: found_segments.append(ThinkingSegment(content=content, marker="Thinking:"))
found_segments.append(ThinkingSegment(content=content, marker="Thinking:"))
return "\n\n" return "\n\n"
res = thinking_colon_pattern.sub(replace_func, txt) res = thinking_colon_pattern.sub(replace_func, txt)
@@ -55,5 +51,4 @@ def parse_thinking_trace(text: str) -> Tuple[List[ThinkingSegment], str]:
colon_segments, final_remaining = extract_colon_blocks(remaining) colon_segments, final_remaining = extract_colon_blocks(remaining)
segments.extend(colon_segments) segments.extend(colon_segments)
return segments, final_remaining.strip() return segments, final_remaining.strip()
+6 -12
View File
@@ -51,19 +51,13 @@ class ToolBiasEngine:
for cat_tools in preset.categories.values(): for cat_tools in preset.categories.values():
for t in cat_tools: for t in cat_tools:
if not isinstance(t, Tool): continue if not isinstance(t, Tool): continue
if t.weight >= 5: if t.weight >= 5: preferred.append(f"{t.name} [HIGH PRIORITY]")
preferred.append(f"{t.name} [HIGH PRIORITY]") elif t.weight == 4: preferred.append(f"{t.name} [PREFERRED]")
elif t.weight == 4: elif t.weight == 2: low_priority.append(f"{t.name} [NOT RECOMMENDED]")
preferred.append(f"{t.name} [PREFERRED]") elif t.weight <= 1: low_priority.append(f"{t.name} [LOW PRIORITY]")
elif t.weight == 2:
low_priority.append(f"{t.name} [NOT RECOMMENDED]")
elif t.weight <= 1:
low_priority.append(f"{t.name} [LOW PRIORITY]")
if preferred: if preferred: lines.append(f"Preferred tools: {', '.join(preferred)}.")
lines.append(f"Preferred tools: {', '.join(preferred)}.") if low_priority: lines.append(f"Low-priority tools: {', '.join(low_priority)}.")
if low_priority:
lines.append(f"Low-priority tools: {', '.join(low_priority)}.")
if global_bias.category_multipliers: if global_bias.category_multipliers:
lines.append("Category focus multipliers:") lines.append("Category focus multipliers:")
-1
View File
@@ -62,7 +62,6 @@ class ToolPresetManager:
def load_all(self) -> Dict[str, ToolPreset]: def load_all(self) -> Dict[str, ToolPreset]:
""" """
Backward compatibility for load_all(). Backward compatibility for load_all().
[C: tests/test_persona_manager.py:test_delete_persona, tests/test_persona_manager.py:test_load_all_merged, tests/test_persona_manager.py:test_save_persona, tests/test_preset_manager.py:test_delete_preset, tests/test_preset_manager.py:test_load_all_merged, tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project] [C: tests/test_persona_manager.py:test_delete_persona, tests/test_persona_manager.py:test_load_all_merged, tests/test_persona_manager.py:test_save_persona, tests/test_preset_manager.py:test_delete_preset, tests/test_preset_manager.py:test_load_all_merged, tests/test_preset_manager.py:test_save_preset_global, tests/test_preset_manager.py:test_save_preset_project, tests/test_presets.py:TestPresetManager.test_delete_preset, tests/test_presets.py:TestPresetManager.test_project_overwrites_global, tests/test_presets.py:TestPresetManager.test_save_and_load_global, tests/test_presets.py:TestPresetManager.test_save_and_load_project]
""" """
-1
View File
@@ -29,7 +29,6 @@ class WorkspaceManager:
def load_all_profiles(self) -> Dict[str, WorkspaceProfile]: def load_all_profiles(self) -> Dict[str, WorkspaceProfile]:
""" """
Merges global and project profiles into a single dictionary. Merges global and project profiles into a single dictionary.
[C: tests/test_workspace_manager.py:test_delete_profile, tests/test_workspace_manager.py:test_load_all_profiles_merged, tests/test_workspace_manager.py:test_save_profile_global_and_project] [C: tests/test_workspace_manager.py:test_delete_profile, tests/test_workspace_manager.py:test_load_all_profiles_merged, tests/test_workspace_manager.py:test_save_profile_global_and_project]
""" """