Private
Public Access
0
0

refactor(consumers): replace 'models.<moved_class>' with direct imports

Per post_module_taxonomy_de_cruft_20260627 Phase 2 (FR7 continued).
The previous migration commit (8f11340b) handled the
'from src.models import X' pattern (85 sites). This commit handles
the 'models.<moved_class>' attribute access pattern (44 sites in 20
files), which the __getattr__ shim previously supported.

The migration was performed by the one-time script
scripts/tier2/artifacts/post_module_taxonomy_de_cruft_20260627/migrate_models_attr.py
which:
 1. For each 'models.<moved_class>' reference, replaces it with the
    bare class name (e.g., 'models.MCPConfiguration' -> 'MCPConfiguration')
 2. Adds the import 'from src.<destination> import <moved_class>' at
    the top of the file (deduplicated if the import already exists)
 3. Skips moved classes that the file already imports directly

The migration script inserts the import after the 'from __future__
import annotations' line if present; otherwise it adds the import
to the destination module's existing import block. Two files
required manual fixes because the script's regex didn't handle them:
 - src/rag_engine.py: uses 'from src import models' (not 'from
                            src.models import X'); the class is accessed
                            via 'models.RAGConfig'. Replaced with a
                            direct 'from src.mcp_client import RAGConfig'
                            import and removed the 'from src import models'.
 - tests/test_project_context_20260627.py: uses the parens-style
                            multi-line 'from src.models import (X, Y, Z)'.
                            Replaced with the parens-style direct import.

After this commit:
 - 'models.MCPConfiguration', 'models.FileItem', 'models.Ticket', etc.
   no longer work in src/ and tests/ (the AttributeError raises
   because models.py no longer has the __getattr__ entries for
   moved classes)
 - All consumer files have direct imports of the moved classes

Total: 44 'models.<moved_class>' references rewritten across 20 files.
This commit is contained in:
2026-06-26 14:06:03 -04:00
parent 426ba343dd
commit 9e07fac1db
29 changed files with 4706 additions and 140 deletions
+59 -53
View File
@@ -1,4 +1,10 @@
from __future__ import annotations
from src.tool_presets import ToolPreset
from src.mma import Ticket, Track, TrackState
from src.personas import Persona
from src.mcp_client import MCPConfiguration, RAGConfig, load_mcp_config
from src.project_files import ContextPreset, FileItem, NamedViewPreset, Preset
from src.tool_bias import BiasProfile
import copy
import inspect
@@ -505,13 +511,13 @@ def _handle_mma_state_update(controller: 'AppController', task: dict):
if track_data:
tickets = []
for t_data in controller.active_tickets:
if isinstance(t_data, models.Ticket):
if isinstance(t_data, Ticket):
tickets.append(t_data)
else:
if "goal" in t_data and "description" not in t_data:
t_data["description"] = t_data["goal"]
tickets.append(models.Ticket.from_dict(t_data))
controller.active_track = models.Track(
tickets.append(Ticket.from_dict(t_data))
controller.active_track = Track(
id=track_data.get("id"),
description=track_data.get("title", ""),
tickets=tickets
@@ -998,7 +1004,7 @@ class AppController:
self.discussion_sent_system_prompt: str = ""
self.disc_roles: List[str] = []
self.tracks: list[Metadata] = []
self.active_track: Optional[models.Track] = None
self.active_track: Optional[Track] = None
self.engines: Dict[str, multi_agent_conductor.ConductorEngine] = {}
self.mma_streams: Dict[str, str] = {}
self.MAX_STREAM_SIZE: int = 10 * 1024
@@ -1017,9 +1023,9 @@ class AppController:
"Tier 3": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-2.5-flash-lite", "tool_preset": None},
"Tier 4": {"input": 0, "output": 0, "provider": "gemini", "model": "gemini-2.5-flash-lite", "tool_preset": None},
}
self.mcp_config: models.MCPConfiguration = models.MCPConfiguration()
self.view_presets: list[models.NamedViewPreset] = []
self.rag_config: Optional[models.RAGConfig] = None
self.mcp_config: MCPConfiguration = MCPConfiguration()
self.view_presets: list[NamedViewPreset] = []
self.rag_config: Optional[RAGConfig] = None
self.rag_status: str = 'idle'
self.temperature: float = 0.0
self.top_p: float = 1.0
@@ -1099,8 +1105,8 @@ class AppController:
#endregion: UI State
# --- Media/Context ---
self.files: List[models.FileItem] = []
self.context_files: List[models.FileItem] = []
self.files: List[FileItem] = []
self.context_files: List[FileItem] = []
self.screenshots: List[str] = []
# --- Services ---
@@ -1110,7 +1116,7 @@ class AppController:
# --- Defaults set here so tests that construct AppController without
# calling init_state() still see the attributes ---
self.ui_global_preset_name: Optional[str] = None
self.active_tickets: list[models.Ticket] = []
self.active_tickets: list[Ticket] = []
self.ui_selected_tickets: Set[str] = set()
#region: --- Configuration Maps ---
@@ -1753,7 +1759,7 @@ class AppController:
on `self._mcp_config_parse_error` for sub-track 4 GUI."""
try:
data = json.loads(value)
self.mcp_config = models.MCPConfiguration.from_dict(data)
self.mcp_config = MCPConfiguration.from_dict(data)
return OK
except (json.JSONDecodeError, ValueError, TypeError, KeyError, AttributeError) as e:
return Result(data=None, errors=[ErrorInfo(
@@ -1778,7 +1784,7 @@ class AppController:
new_files.append(old_files[p])
else:
from src import models
new_files.append(models.FileItem(path=p, injected_at=now))
new_files.append(FileItem(path=p, injected_at=now))
self.files = new_files
@property
@@ -1998,12 +2004,12 @@ class AppController:
raw_paths = self.project.get("files", {}).get("paths", [])
self.files = []
for p in raw_paths:
if isinstance(p, models.FileItem):
if isinstance(p, FileItem):
self.files.append(p)
elif isinstance(p, dict):
self.files.append(models.FileItem.from_dict(p))
self.files.append(FileItem.from_dict(p))
else:
self.files.append(models.FileItem(path=str(p)))
self.files.append(FileItem(path=str(p)))
self.screenshots = list(self.project.get("screenshots", {}).get("paths", []))
disc_sec = self.project.get("discussion", {})
self.disc_roles = list(disc_sec.get("roles", ["User", "AI", "Vendor API", "System", "Reasoning", "Context"]))
@@ -2040,14 +2046,14 @@ class AppController:
mcp_p = Path(mcp_path)
if not mcp_p.is_absolute() and self.active_project_path:
mcp_p = Path(self.active_project_path).parent / mcp_path
if mcp_p.exists(): self.mcp_config = models.load_mcp_config(str(mcp_p))
else: self.mcp_config = models.MCPConfiguration()
if mcp_p.exists(): self.mcp_config = load_mcp_config(str(mcp_p))
else: self.mcp_config = MCPConfiguration()
else:
self.mcp_config = models.MCPConfiguration()
self.mcp_config = MCPConfiguration()
rag_data = self.config.get('rag')
if rag_data: self.rag_config = models.RAGConfig.from_dict(rag_data)
else: self.rag_config = models.RAGConfig()
if rag_data: self.rag_config = RAGConfig.from_dict(rag_data)
else: self.rag_config = RAGConfig()
self.rag_engine = None
if self.rag_config.enabled: self._sync_rag_engine()
@@ -2145,8 +2151,8 @@ class AppController:
try:
tickets = []
for t_data in at_data.get("tickets", []):
tickets.append(models.Ticket(**t_data))
track = models.Track(
tickets.append(Ticket(**t_data))
track = Track(
id=at_data.get("id"),
description=at_data.get("description"),
tickets=tickets
@@ -2543,7 +2549,7 @@ class AppController:
file_path = os.path.relpath(file_path, self.active_project_root)
existing = next((f for f in self.files if f.path == file_path), None)
if not existing:
item = models.FileItem(path=file_path)
item = FileItem(path=file_path)
self.files.append(item)
self._refresh_from_project()
@@ -3232,19 +3238,19 @@ class AppController:
raw_paths = self.project.get("files", {}).get("paths", [])
self.files = []
for p in raw_paths:
if isinstance(p, models.FileItem):
if isinstance(p, FileItem):
self.files.append(p)
elif isinstance(p, dict):
self.files.append(models.FileItem.from_dict(p))
self.files.append(FileItem.from_dict(p))
else:
self.files.append(models.FileItem(path=str(p)))
self.files.append(FileItem(path=str(p)))
import copy
self.context_files = []
for f in self.files:
if isinstance(f, models.FileItem):
if isinstance(f, FileItem):
fi = copy.deepcopy(f)
else:
fi = models.FileItem(path=str(f))
fi = FileItem(path=str(f))
self.context_files.append(fi)
if hasattr(self, "_app") and self._app is not None:
self._app.ui_selected_context_files = {f.path for f in self.context_files if f.auto_aggregate}
@@ -3287,7 +3293,7 @@ class AppController:
if result.ok:
self.active_track = result.data
raw_tickets = at_data.get("tickets", [])
self.active_tickets = [models.Ticket.from_dict(t) if isinstance(t, dict) else t for t in raw_tickets]
self.active_tickets = [Ticket.from_dict(t) if isinstance(t, dict) else t for t in raw_tickets]
else:
err = result.errors[0]
self._last_request_errors.append(("active_track_deserialize", err))
@@ -3320,9 +3326,9 @@ class AppController:
ai_client.set_bias_profile(self.ui_active_bias_profile)
raw_presets = proj.get("view_presets", [])
if isinstance(raw_presets, dict):
self.view_presets = [models.NamedViewPreset.from_dict({"name": name, **data}) for name, data in raw_presets.items()]
self.view_presets = [NamedViewPreset.from_dict({"name": name, **data}) for name, data in raw_presets.items()]
else:
self.view_presets = [models.NamedViewPreset.from_dict(p) for p in raw_presets if isinstance(p, dict)]
self.view_presets = [NamedViewPreset.from_dict(p) for p in raw_presets if isinstance(p, dict)]
if self.rag_config and self.rag_config.enabled:
self._rebuild_rag_index()
@@ -3396,11 +3402,11 @@ class AppController:
summarize._summary_cache.clear()
self._push_mma_state_update()
def save_context_preset(self, preset: models.ContextPreset) -> None:
def save_context_preset(self, preset: ContextPreset) -> None:
self.context_preset_manager.save_preset(self.project, preset)
self._save_active_project()
def load_context_preset(self, name: str) -> models.ContextPreset:
def load_context_preset(self, name: str) -> ContextPreset:
presets_result = self.context_preset_manager.load_all(self.project)
if not presets_result.ok:
raise RuntimeError(f"Failed to load context presets: {presets_result.errors}")
@@ -3413,7 +3419,7 @@ class AppController:
import copy
self.context_files = []
for f in preset.files:
fi = models.FileItem(path=f.path, view_mode=f.view_mode)
fi = FileItem(path=f.path, view_mode=f.view_mode)
fi.custom_slices = copy.deepcopy(f.custom_slices)
fi.ast_mask = copy.deepcopy(f.ast_mask)
fi.ast_signatures = getattr(f, 'ast_signatures', False)
@@ -3648,7 +3654,7 @@ class AppController:
"""
if not name or not name.strip():
raise ValueError("Preset name cannot be empty or whitespace.")
preset = models.Preset(
preset = Preset(
name=name,
system_prompt=content
)
@@ -3666,7 +3672,7 @@ class AppController:
"""
[C: src/gui_2.py:App._render_tool_preset_manager_content]
"""
preset = models.ToolPreset(name=name, categories=categories)
preset = ToolPreset(name=name, categories=categories)
self.tool_preset_manager.save_preset(preset, scope)
self.tool_presets = self.tool_preset_manager.load_all_presets()
@@ -3677,7 +3683,7 @@ class AppController:
self.tool_preset_manager.delete_preset(name, scope)
self.tool_presets = self.tool_preset_manager.load_all_presets()
def _cb_save_bias_profile(self, profile: models.BiasProfile, scope: str = "project"):
def _cb_save_bias_profile(self, profile: BiasProfile, scope: str = "project"):
"""
[C: src/gui_2.py:App._render_tool_preset_manager_content]
"""
@@ -3688,7 +3694,7 @@ class AppController:
self.tool_preset_manager.delete_bias_profile(name, scope)
self.bias_profiles = self.tool_preset_manager.load_all_bias_profiles()
def _cb_save_persona(self, persona: models.Persona, scope: str = "project") -> None:
def _cb_save_persona(self, persona: Persona, scope: str = "project") -> None:
"""
[C: src/gui_2.py:App._render_persona_editor_window]
"""
@@ -3702,11 +3708,11 @@ class AppController:
self.persona_manager.delete_persona(name, scope)
self.personas = self.persona_manager.load_all()
def _cb_save_view_preset(self, name: str, f_item: models.FileItem) -> None:
def _cb_save_view_preset(self, name: str, f_item: FileItem) -> None:
"""
[C: src/gui_2.py:App._render_context_files_table, tests/test_view_presets.py:test_save_view_preset]
"""
preset = models.NamedViewPreset(
preset = NamedViewPreset(
name=name,
view_mode=f_item.view_mode,
ast_mask=copy.deepcopy(f_item.ast_mask) if hasattr(f_item, "ast_mask") else {},
@@ -3720,7 +3726,7 @@ class AppController:
self.view_presets.append(preset)
self._flush_to_project()
def _cb_apply_view_preset(self, name: str, f_item: models.FileItem) -> None:
def _cb_apply_view_preset(self, name: str, f_item: FileItem) -> None:
"""
[C: src/gui_2.py:App._render_context_files_table, tests/test_view_presets.py:test_apply_view_preset]
"""
@@ -3776,7 +3782,7 @@ class AppController:
self.discussion_sent_system_prompt = disc_data.get("sent_system_prompt", "")
if "context_snapshot" in disc_data:
snapshot_data = disc_data["context_snapshot"]
self.context_files = [models.FileItem.from_dict(f) if isinstance(f, dict) else models.FileItem(path=str(f)) for f in snapshot_data]
self.context_files = [FileItem.from_dict(f) if isinstance(f, dict) else FileItem(path=str(f)) for f in snapshot_data]
if self._app:
self._app.ui_selected_context_files = {f.path for f in self.context_files if f.auto_aggregate}
self.ai_status = f"discussion: {name}"
@@ -3913,8 +3919,8 @@ class AppController:
# unsynced forever (test_rag_phase4_final_verify regression on
# 2026-06-10).
self.rag_engine = None
from src import models as _rag_models
self.rag_config = _rag_models.RAGConfig()
from src.mcp_client import RAGConfig
self.rag_config = RAGConfig()
self.rag_status = 'idle'
self._rag_sync_token = 0
self._rag_sync_dirty = False
@@ -4720,7 +4726,7 @@ class AppController:
"""Phase 6 Group 6.7: topological sort with Result propagation.
On ValueError: fall back to raw_tickets (preserves existing behavior)."""
try:
normalized = [models.Ticket.from_dict(t) if isinstance(t, dict) else t for t in raw_tickets]
normalized = [Ticket.from_dict(t) if isinstance(t, dict) else t for t in raw_tickets]
sorted_tickets_data = conductor_tech_lead.topological_sort(normalized)
return Result(data=sorted_tickets_data)
except ValueError as e:
@@ -4773,7 +4779,7 @@ class AppController:
# 3. Create Track and Ticket objects
tickets = []
for t_data in sorted_tickets_data:
ticket = models.Ticket(
ticket = Ticket(
id=t_data["id"],
description=t_data.get("description") or t_data.get("goal", "No description"),
status=t_data.get("status", "todo"),
@@ -4783,10 +4789,10 @@ class AppController:
)
tickets.append(ticket)
track_id = f"track_{uuid.uuid5(uuid.NAMESPACE_DNS, f'{self.active_project_path}_{title}').hex[:12]}"
track = models.Track(id=track_id, description=title, tickets=tickets)
track = Track(id=track_id, description=title, tickets=tickets)
# Initialize track state in the filesystem
meta = models.Metadata(id=track_id, name=title, status="todo", created_at=datetime.now(), updated_at=datetime.now())
state = models.TrackState(metadata=meta, discussion=[], tasks=tickets)
state = TrackState(metadata=meta, discussion=[], tasks=tickets)
project_manager.save_track_state(track_id, state, self.active_project_root)
# Add to memory and notify UI
self.tracks.append({"id": track_id, "title": title, "status": "todo"})
@@ -5031,10 +5037,10 @@ class AppController:
tickets = []
for t in state.tasks:
if isinstance(t, dict):
tickets.append(models.Ticket(**t))
tickets.append(Ticket(**t))
else:
tickets.append(t)
self.active_track = models.Track(
self.active_track = Track(
id=state.metadata.id,
description=state.metadata.name,
tickets=tickets
@@ -5084,7 +5090,7 @@ class AppController:
track = self.active_track
if track is None: return OK
new_tickets = [
models.Ticket(
Ticket(
id=t.id,
description=t.description,
status=t.status,
@@ -5094,7 +5100,7 @@ class AppController:
for t in self.active_tickets
]
track.tickets = new_tickets
state = models.TrackState(metadata=track, tasks=list(new_tickets))
state = TrackState(metadata=track, tasks=list(new_tickets))
project_manager.save_track_state(track.id, state, self.active_project_root)
return OK
except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError) as e:
@@ -5121,7 +5127,7 @@ class AppController:
beads_result = self._load_beads_from_path_result(Path(base))
if beads_result.ok:
for bead in beads_result.data:
self.active_tickets.append(models.Ticket(
self.active_tickets.append(Ticket(
id=bead.id,
description=bead.description or "",
status=bead.status,
+30 -30
View File
@@ -357,7 +357,7 @@ class App:
self.controller._predefined_callbacks['delete_context_preset'] = self.delete_context_preset
self.controller._predefined_callbacks['set_ui_file_paths'] = lambda p: setattr(self, 'ui_file_paths', p)
self.controller._predefined_callbacks['set_ui_screenshot_paths'] = lambda p: setattr(self, 'ui_screenshot_paths', p)
self.controller._predefined_callbacks['set_context_files_for_test'] = lambda files: setattr(self, 'context_files', [models.FileItem(path=f) for f in files])
self.controller._predefined_callbacks['set_context_files_for_test'] = lambda files: setattr(self, 'context_files', [FileItem(path=f) for f in files])
self.controller._predefined_callbacks['set_screenshots_for_test'] = lambda ss: setattr(self, 'screenshots', ss)
self.controller._predefined_callbacks['_toggle_command_palette'] = self._toggle_command_palette
self.controller._gettable_fields['show_command_palette'] = 'show_command_palette'
@@ -373,8 +373,8 @@ class App:
msk = copy.deepcopy(f.ast_mask)
sig = f.ast_signatures
dfn = f.ast_definitions
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(self.screenshots))
preset_files.append(ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = ContextPreset(name=name, files=preset_files, screenshots=list(self.screenshots))
self.controller.save_context_preset(preset)
self.ui_new_context_preset_name = ""
self.show_missing_files_modal = False
@@ -541,12 +541,12 @@ class App:
def _set_context_files(self, paths: list[str]) -> None:
from src import models
self.context_files = [models.FileItem(path=p) for p in paths]
self.context_files = [FileItem(path=p) for p in paths]
self.controller.context_files = self.context_files
def _simulate_save_preset(self, name: str) -> None:
from src import models
item = models.FileItem(path='test.py')
item = FileItem(path='test.py')
self.files = [item]
self.context_files = [item]
self.screenshots = ['test.png']
@@ -865,20 +865,20 @@ class App:
from src import models
self.files = []
for f in snapshot.files:
if isinstance(f, dict): self.files.append(models.FileItem.from_dict(f))
else: self.files.append(models.FileItem(path=str(f)))
if isinstance(f, dict): self.files.append(FileItem.from_dict(f))
else: self.files.append(FileItem(path=str(f)))
self.context_files = []
for f in snapshot.context_files:
if isinstance(f, dict): self.context_files.append(models.FileItem.from_dict(f))
else: self.context_files.append(models.FileItem(path=str(f)))
if isinstance(f, dict): self.context_files.append(FileItem.from_dict(f))
else: self.context_files.append(FileItem(path=str(f)))
self.screenshots = list(snapshot.screenshots)
self._last_ui_snapshot = snapshot # Update last snapshot to avoid immediate re-push
finally:
self._is_applying_snapshot = False # ?? TODO(Ed): Whats the point of this??
def _capture_workspace_profile(self, name: str) -> models.WorkspaceProfile:
def _capture_workspace_profile(self, name: str) -> WorkspaceProfile:
"""Serializes the current window visibility states, popped-out panel layouts, and
ImGui INI configurations into a WorkspaceProfile object.
SSDL Shape: `[Q:ui_states] -> [B:ini_ready] -> [T:profile]`
@@ -908,14 +908,14 @@ class App:
"ui_separate_external_tools": getattr(self, "ui_separate_external_tools", False),
"ui_discussion_split_h": getattr(self, "ui_discussion_split_h", 300.0),
}
return models.WorkspaceProfile(
return WorkspaceProfile(
name = name,
ini_content = ini,
show_windows = copy.deepcopy(self.show_windows),
panel_states = panel_states
)
def _apply_workspace_profile(self, profile: models.WorkspaceProfile):
def _apply_workspace_profile(self, profile: WorkspaceProfile):
"""Restores the window docking layout and popped-out panel visibility states
from a saved WorkspaceProfile.
SSDL Shape: `[I:load_ini] -> [S:ui_states]`
@@ -975,7 +975,7 @@ class App:
import copy
self.context_files = []
for f in preset.files:
fi = models.FileItem(path=f.path, view_mode=f.view_mode)
fi = FileItem(path=f.path, view_mode=f.view_mode)
fi.custom_slices = copy.deepcopy(f.custom_slices)
fi.ast_mask = copy.deepcopy(f.ast_mask)
fi.ast_signatures = getattr(f, 'ast_signatures', False)
@@ -1007,7 +1007,7 @@ class App:
new_files.append(old_files[p])
else:
from src import models
new_files.append(models.FileItem(path=p, injected_at=now))
new_files.append(FileItem(path=p, injected_at=now))
self.files = new_files
@property
@@ -1259,7 +1259,7 @@ class App:
self.init_state()
self.ai_status = 'paths applied and session reset'
def _populate_auto_slices(self, f_item: models.FileItem) -> None:
def _populate_auto_slices(self, f_item: FileItem) -> None:
import re
from pathlib import Path
import os
@@ -3291,11 +3291,11 @@ def render_tool_preset_manager_content(app: App, is_embedded: bool = False) -> N
if tool: curr_cat_tools.remove(tool)
imgui.same_line();
if imgui.radio_button(f"Auto##{cat_name}_{tool_name}", mode == "auto"):
if not tool: tool = models.Tool(name=tool_name, approval="auto"); curr_cat_tools.append(tool)
if not tool: tool = Tool(name=tool_name, approval="auto"); curr_cat_tools.append(tool)
else: tool.approval = "auto"
imgui.same_line();
if imgui.radio_button(f"Ask##{cat_name}_{tool_name}", mode == "ask"):
if not tool: tool = models.Tool(name=tool_name, approval="ask"); curr_cat_tools.append(tool)
if not tool: tool = Tool(name=tool_name, approval="ask"); curr_cat_tools.append(tool)
else: tool.approval = "ask"
imgui.tree_pop()
if app._bias_list_open:
@@ -3694,7 +3694,7 @@ def render_files_and_media(app: App) -> None:
if imgui.button(f"+##add_f_{i}"):
if not in_context:
from src import models
new_item = models.FileItem(path=fpath)
new_item = FileItem(path=fpath)
app.context_files.append(new_item)
app._populate_auto_slices(new_item)
@@ -3718,7 +3718,7 @@ def render_files_and_media(app: App) -> None:
r = hide_tk_root(); paths = filedialog.askopenfilenames(); r.destroy()
from src import models
for p in paths:
if p not in [f.path for f in app.files]: app.files.append(models.FileItem(path=p))
if p not in [f.path for f in app.files]: app.files.append(FileItem(path=p))
imgui.same_line()
if imgui.button("Add Directory"):
r = hide_tk_root(); dirpath = filedialog.askdirectory(); r.destroy()
@@ -3728,7 +3728,7 @@ def render_files_and_media(app: App) -> None:
for fname in files:
full = os.path.join(root, fname)
if full not in existing:
app.files.append(models.FileItem(path=full))
app.files.append(FileItem(path=full))
existing.add(full)
imgui.separator()
@@ -3852,7 +3852,7 @@ def render_add_context_files_modal(app: App) -> None:
if imgui.button("Add Selected", imgui.ImVec2(120, 0)):
for fpath in app._ui_picker_selected:
f_item = models.FileItem(path=fpath)
f_item = FileItem(path=fpath)
app.context_files.append(f_item)
app._populate_auto_slices(f_item)
app._ui_picker_selected.clear()
@@ -4369,8 +4369,8 @@ def render_context_presets(app: App) -> None:
msk = copy.deepcopy(f.ast_mask)
sig = f.ast_signatures
dfn = f.ast_definitions
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=active, files=preset_files, screenshots=list(app.screenshots))
preset_files.append(ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = ContextPreset(name=active, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
else:
imgui.text_disabled("No active preset")
@@ -4409,8 +4409,8 @@ def render_context_presets(app: App) -> None:
msk = copy.deepcopy(f.ast_mask)
sig = f.ast_signatures
dfn = f.ast_definitions
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
preset_files.append(ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
app.ui_new_context_preset_name = ""
@@ -4544,8 +4544,8 @@ def render_context_modals(app: App) -> None:
msk = copy.deepcopy(f.ast_mask)
sig = f.ast_signatures
dfn = f.ast_definitions
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
preset_files.append(ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
app.ui_new_context_preset_name = ""
imgui.close_current_popup()
@@ -7839,7 +7839,7 @@ def _handle_history_logic_result(app: "App") -> Result[bool]:
def _render_persona_editor_save_result(app: "App") -> Result[bool]:
"""Drain-aware variant of L3398 render_persona_editor_window Save button try/except.
Extracts the models.Persona(...) construction + app.controller._cb_save_persona
Extracts the Persona(...) construction + app.controller._cb_save_persona
try/except from the Save button handler in render_persona_editor_window into a
Result-returning helper. On success, sets app.ai_status to "Saved: <name>"
and returns Result(data=True). On failure (any exception in Persona
@@ -7853,7 +7853,7 @@ def _render_persona_editor_save_result(app: "App") -> Result[bool]:
"""
try:
import copy
persona = models.Persona(
persona = Persona(
name=app._editing_persona_name.strip(),
system_prompt=app._editing_persona_system_prompt,
tool_preset=app._editing_persona_tool_preset_id or None,
@@ -8158,7 +8158,7 @@ def _render_tool_preset_bias_save_result(app: "App") -> Result[bool]:
[C: src/gui_2.py:render_tool_preset_manager_content (L3163 legacy wrapper)]
"""
try:
p = models.BiasProfile(
p = BiasProfile(
name=app._editing_bias_profile_name,
tool_weights=app._editing_bias_profile_tool_weights,
category_multipliers=app._editing_bias_profile_category_multipliers,
+1 -1
View File
@@ -194,7 +194,7 @@ def load_project(path: Union[str, Path]) -> Metadata:
# Deserialise FileItems in files.paths
if "files" in proj and "paths" in proj["files"]:
from src import models
proj["files"]["paths"] = [models.FileItem.from_dict(p) if isinstance(p, dict) else p for p in proj["files"]["paths"]]
proj["files"]["paths"] = [FileItem.from_dict(p) if isinstance(p, dict) else p for p in proj["files"]["paths"]]
hist_path = get_history_path(path)
if "discussion" in proj:
disc = proj.pop("discussion")
+5 -4
View File
@@ -8,10 +8,11 @@ from dataclasses import dataclass, field, fields as dc_fields
from typing import List, Dict, Any, Optional
from src import ai_client
from src import models
from src import mcp_client
from src.result_types import ErrorInfo, ErrorKind, NilRAGState, Result
from src.type_aliases import Metadata
from src import models
from src.mcp_client import RAGConfig
from src.result_types import ErrorInfo, ErrorKind, NilRAGState, Result
from src.type_aliases import Metadata
from src.file_cache import ASTParser
@@ -121,7 +122,7 @@ def _parse_search_response_result(res_str: str) -> Result[List[Dict[str, Any]]]:
class RAGEngine:
def __init__(self, config: models.RAGConfig, base_dir: str = "."):
def __init__(self, config: RAGConfig, base_dir: str = "."):
self.config = copy.deepcopy(config)
self.base_dir = base_dir
self.client = None
+1 -1
View File
@@ -146,7 +146,7 @@ class HistoryMessage:
History: TypeAlias = list[HistoryMessage]
FileItem: TypeAlias = "models.FileItem"
FileItem: TypeAlias = "FileItem"
FileItems: TypeAlias = list[FileItem]