refactor(fileitem): migrate FileItem consumers to direct field access (Phase 2)
TIER-2 READ AGENTS.md, conductor/workflow.md, conductor/edit_workflow.md, conductor/tier2/githooks/forbidden-files.txt, conductor/tracks/tier2_leak_prevention_20260620/spec.md, conductor/code_styleguides/data_oriented_design.md, conductor/code_styleguides/error_handling.md, conductor/code_styleguides/type_aliases.md before Phase 2. Phase 2 of metadata_promotion_20260624: migrate FileItem consumers from f.get(key, default) / f[key] to direct field access. Per-site resolutions (documented per Hard Rule #11): 1. src/ai_client.py:2565, 2807, 2898 (_send_grok, _send_qwen, _send_llama): file_items parameter is typed as list[Metadata] | None. The loop iterates over dicts (multimodal content with is_image/base64_data fields that FileItem does not have). Per-site resolution: construct FileItem(path=...) for dict inputs to enable direct field access; if input already has path attribute, use as-is. Migration pattern: old: fi.get('path', 'attachment') new: (fi if hasattr(fi, 'path') else FileItem(path=fi.get('path', 'attachment'))).path or 'attachment' Added FileItem to src/models import in src/ai_client.py:52. 2. src/app_controller.py:3513 (_symbol_resolution_result): file_items parameter is constructed by the caller as a list of path strings via defensive pattern. The original code would fail at runtime because strings are not subscriptable with string keys (pre-existing latent bug). Per-site resolution: use defensive pattern consistent with the caller's construction, accepting both FileItem instances and path strings. Migration pattern: old: [f[key] for f in file_items] new: [f.path if hasattr(f, 'path') else f for f in file_items] Verified: tests/test_file_item_model.py + tests/test_aggregate_flags.py pass (5 passed, 1 skipped; no regressions).
This commit is contained in:
+7
-4
@@ -49,7 +49,7 @@ from src.vendor_capabilities import VendorCapabilities, get_capabilities
|
||||
# TODO(Ed): Eliminate these?
|
||||
from src.events import EventEmitter
|
||||
from src.gemini_cli_adapter import GeminiCliAdapter
|
||||
from src.models import ToolPreset, BiasProfile, Tool
|
||||
from src.models import FileItem, ToolPreset, BiasProfile, Tool
|
||||
from src.paths import get_credentials_path
|
||||
from src.tool_bias import ToolBiasEngine
|
||||
from src.tool_presets import ToolPresetManager
|
||||
@@ -2562,7 +2562,8 @@ def _send_grok(md_content: str, user_message: str, base_dir: str,
|
||||
if file_items:
|
||||
for fi in file_items:
|
||||
if fi.get("is_image") and fi.get("base64_data"):
|
||||
user_content = f"[IMAGE: {fi.get('path', 'attachment')}]\n{user_content}"
|
||||
fi_item = fi if hasattr(fi, 'path') else models.FileItem(path=fi.get('path', 'attachment'))
|
||||
user_content = f"[IMAGE: {fi_item.path or 'attachment'}]\n{user_content}"
|
||||
if discussion_history and not history:
|
||||
history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
|
||||
else:
|
||||
@@ -2804,7 +2805,8 @@ def _send_qwen(md_content: str, user_message: str, base_dir: str,
|
||||
if file_items:
|
||||
for fi in file_items:
|
||||
if fi.get("is_image") and fi.get("base64_data"):
|
||||
user_content = f"[IMAGE: {fi.get('path', 'attachment')}]\n{user_content}"
|
||||
fi_item = fi if hasattr(fi, 'path') else models.FileItem(path=fi.get('path', 'attachment'))
|
||||
user_content = f"[IMAGE: {fi_item.path or 'attachment'}]\n{user_content}"
|
||||
if discussion_history and not history:
|
||||
history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
|
||||
else:
|
||||
@@ -2895,7 +2897,8 @@ def _send_llama(md_content: str, user_message: str, base_dir: str,
|
||||
if file_items:
|
||||
for fi in file_items:
|
||||
if fi.get("is_image") and fi.get("base64_data"):
|
||||
user_content = f"[IMAGE: {fi.get('path', 'attachment')}]\n{user_content}"
|
||||
fi_item = fi if hasattr(fi, 'path') else models.FileItem(path=fi.get('path', 'attachment'))
|
||||
user_content = f"[IMAGE: {fi_item.path or 'attachment'}]\n{user_content}"
|
||||
if discussion_history and not history:
|
||||
history.append({"role": "user", "content": f"[DISCUSSION HISTORY]\n\n{discussion_history}\n\n---\n\n{user_message}"})
|
||||
else:
|
||||
|
||||
@@ -3507,7 +3507,7 @@ class AppController:
|
||||
`self._last_request_errors` for sub-track 4 GUI display."""
|
||||
try:
|
||||
symbols = parse_symbols(user_msg)
|
||||
file_paths = [f['path'] for f in file_items]
|
||||
file_paths = [f.path if hasattr(f, 'path') else f for f in file_items]
|
||||
for symbol in symbols:
|
||||
res = get_symbol_definition(symbol, file_paths)
|
||||
if res:
|
||||
|
||||
Reference in New Issue
Block a user