feat(memory): fix silent catch violations — add logger calls to all except blocks

Co-Authored-By: @memory <memory@aipass>
This commit is contained in:
AIOSAI
2026-03-23 12:56:18 -07:00
co-authored by @memory
parent 6bd1bd00f1
commit 88c750cbf0
32 changed files with 243 additions and 78 deletions
@@ -52,6 +52,7 @@ def extract_file_info(file_path: Path) -> Dict[str, Any]:
try:
tree = ast.parse(content)
except SyntaxError:
logger.info(f"[indexer] Syntax error parsing {file_path.name}, skipping AST extraction")
return {
'filename': file_path.name,
'path': str(file_path.relative_to(CODE_ARCHIVE_PATH)),
@@ -85,6 +86,7 @@ def extract_file_info(file_path: Path) -> Dict[str, Any]:
'indexed_at': datetime.now().isoformat()
}
except Exception as e:
logger.warning(f"[indexer] Failed to extract file info from {file_path.name}: {e}")
return {
'filename': file_path.name,
'path': str(file_path),
@@ -120,8 +122,8 @@ def load_index() -> Dict[str, Any]:
try:
with open(INDEX_PATH) as f:
return json.load(f)
except Exception:
pass
except Exception as e:
logger.warning(f"[indexer] Failed to load index file: {e}")
return {
'metadata': {
@@ -155,6 +157,7 @@ def save_index(index: Dict[str, Any]) -> Dict[str, Any]:
return {'success': True}
except Exception as e:
logger.error(f"[indexer] Failed to save index: {e}")
return {'success': False, 'error': str(e)}
@@ -89,7 +89,8 @@ def count_chroma_vectors() -> int:
return total
except Exception:
except Exception as e:
logger.warning(f"[central_writer] Failed to count chroma vectors: {e}")
return 0
@@ -112,6 +113,7 @@ def count_archive_files() -> int:
return len(archive_files)
except Exception as e:
logger.error(f"[central_writer] Failed to count archive files: {e}")
raise Exception(f"Failed to count archive files: {e}")
@@ -141,6 +143,7 @@ def get_last_rollover_timestamp() -> str:
return mtime.isoformat()
except Exception as e:
logger.error(f"[central_writer] Failed to get rollover timestamp: {e}")
raise Exception(f"Failed to get rollover timestamp: {e}")
@@ -195,6 +198,7 @@ def read_central_file() -> Dict[str, Any]:
return json_load(f)
except Exception as e:
logger.error(f"[central_writer] Failed to read central file: {e}")
raise Exception(f"Failed to read central file: {e}")
@@ -216,6 +220,7 @@ def write_central_file(data: Dict[str, Any]) -> None:
json_dump(data, f, indent=2, ensure_ascii=False)
except Exception as e:
logger.error(f"[central_writer] Failed to write central file: {e}")
raise Exception(f"Failed to write central file: {e}")
@@ -276,6 +281,7 @@ def update_central(verbose: bool = False) -> Dict[str, Any]:
return result
except Exception as e:
logger.error(f"[central_writer] Failed to update central: {e}")
return {
"success": False,
"error": str(e)
@@ -303,6 +309,7 @@ def get_current_stats() -> Dict[str, Any]:
}
except Exception as e:
logger.warning(f"[central_writer] Failed to get current stats: {e}")
return {
"success": False,
"error": str(e)
@@ -80,7 +80,8 @@ def _read_central_stats() -> Dict[str, Any]:
"total_archives": stats.get("total_archives", 0),
"last_rollover": stats.get("last_rollover", "")
}
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to read central stats: {e}")
return {"total_vectors": 0, "total_archives": 0, "last_rollover": ""}
@@ -104,7 +105,8 @@ def _get_collections_count() -> int:
count = cursor.fetchone()[0]
conn.close()
return count
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to count collections: {e}")
return 0
@@ -125,7 +127,8 @@ def _get_rollover_config() -> Dict[str, Any]:
"defaults": rollover.get("defaults", {"max_lines": 600, "buffer": 100}),
"per_branch": rollover.get("per_branch", {})
}
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to load rollover config: {e}")
return {"defaults": {"max_lines": 600, "buffer": 100}, "per_branch": {}}
@@ -237,11 +240,13 @@ def _find_branches_near_rollover() -> List[Dict[str, Any]]:
"current_lines": current_lines,
"max_lines": max_lines
})
except Exception:
except Exception as e:
# Skip files that can't be read
logger.warning(f"[dashboard_push] Failed to read memory file {memory_file}: {e}")
continue
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to scan branches for rollover: {e}")
return near_rollover # Return partial results on registry read failure
# Sort by lines_remaining ascending (most urgent first)
@@ -262,7 +267,8 @@ def _get_template_version() -> str:
data = json_loads(TEMPLATE_VERSION_FILE.read_text(encoding="utf-8"))
return data.get("version", "unknown")
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to read template version: {e}")
return "unknown"
@@ -283,6 +289,7 @@ def _get_last_rollover_info(central_stats: Dict) -> Dict[str, str]:
dt = datetime.fromisoformat(last_rollover_ts)
return {"date": dt.strftime("%Y-%m-%d")}
except (ValueError, TypeError):
logger.info(f"[dashboard_push] Could not parse rollover timestamp: {last_rollover_ts}")
return {"date": last_rollover_ts}
return {"date": "never"}
@@ -309,7 +316,8 @@ def _get_all_branch_paths() -> List[Path]:
if branch_path.exists():
paths.append(branch_path)
return paths
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to get branch paths: {e}")
return []
@@ -401,7 +409,8 @@ def _write_section_to_all_branches(section_name: str, section_data: Dict,
if result.returncode == 0 and result.stdout.strip().isdigit():
return int(result.stdout.strip())
return 0
except Exception:
except Exception as e:
logger.warning(f"[dashboard_push] Failed to write section to branches: {e}")
return 0
@@ -435,7 +444,8 @@ def push_memory_bank_dashboard() -> bool:
return success_count > 0
except Exception:
except Exception as e:
logger.error(f"[dashboard_push] Failed to push dashboard: {e}")
return False
@@ -147,7 +147,8 @@ def _load_manifest() -> Dict[str, str]:
if _PROCESSED_MANIFEST.exists():
try:
return json.loads(_PROCESSED_MANIFEST.read_text(encoding='utf-8'))
except Exception:
except Exception as e:
logger.warning(f"[plans_processor] Failed to load processed manifest: {e}")
return {}
return {}
@@ -175,6 +176,7 @@ def _embed_texts(texts: List[str]) -> dict:
return {'success': False, 'error': result.stderr or 'Embedding failed'}
return json.loads(result.stdout)
except Exception as e:
logger.warning(f"[plans_processor] Embedding subprocess failed: {e}")
return {'success': False, 'error': str(e)}
@@ -199,6 +201,7 @@ def _store_vectors(embeddings, documents, metadatas, collection_name="flow_plans
return {'success': False, 'error': result.stderr or 'Storage failed'}
return json.loads(result.stdout)
except Exception as e:
logger.warning(f"[plans_processor] Vector storage subprocess failed: {e}")
return {'success': False, 'error': str(e)}
@@ -227,6 +230,7 @@ def process_plans() -> Dict[str, Any]:
config = json.loads(config_path.read_text(encoding='utf-8'))
plans_config = config.get('plans', {})
except Exception as e:
logger.warning(f"[plans_processor] Config load failed: {e}")
return {'success': False, 'error': f'Config load failed: {e}'}
if not plans_config.get('enabled', False):
@@ -273,6 +277,7 @@ def process_plans() -> Dict[str, Any]:
try:
text = plan_file.read_text(encoding='utf-8')
except Exception as e:
logger.warning(f"[plans_processor] Failed to read plan file {plan_file.name}: {e}")
errors.append(f'{plan_file.name}: read error: {e}')
continue
@@ -25,6 +25,7 @@ from pathlib import Path
from datetime import datetime
from typing import List, Dict, Any
from aipass.prax import logger
from aipass.memory.apps.handlers.json import json_handler
# Paths
@@ -47,8 +48,8 @@ def _notify_failure(subject: str, message: str) -> None:
timeout=30,
cwd=str(_MEMORY_ROOT)
)
except Exception:
pass # Best-effort - don't let notification failure break processing
except Exception as e:
logger.warning(f"[pool_processor] Failed to send failure notification: {e}")
def _update_central_and_dashboard() -> None:
@@ -68,8 +69,8 @@ def _update_central_and_dashboard() -> None:
"update_central()"],
capture_output=True, text=True, timeout=30
)
except Exception:
pass # Non-critical: central update failure does not break pool processing
except Exception as e:
logger.warning(f"[pool_processor] Central stats update failed: {e}")
# Push dashboard to all branches
try:
@@ -79,8 +80,8 @@ def _update_central_and_dashboard() -> None:
"push_memory_bank_dashboard()"],
capture_output=True, text=True, timeout=60
)
except Exception:
pass # Non-critical: dashboard push failure does not break pool processing
except Exception as e:
logger.warning(f"[pool_processor] Dashboard push failed: {e}")
def find_source_file(filename: str) -> Path | None:
@@ -115,6 +116,7 @@ def load_config() -> dict:
config = json.load(f)
return config.get('memory_pool', {})
except Exception as e:
logger.warning(f"[pool_processor] Failed to load config: {e}")
return {'enabled': False, 'error': str(e)}
@@ -166,6 +168,7 @@ def read_file_content(file_path: Path) -> dict:
}
}
except Exception as e:
logger.warning(f"[pool_processor] Failed to read file content: {e}")
return {'success': False, 'error': str(e)}
@@ -286,6 +289,7 @@ def process_file_to_vectors(file_path: Path, collection_name: str, chunk_size: i
}
except Exception as e:
logger.warning(f"[pool_processor] Failed to process file to vectors: {e}")
return {'success': False, 'error': str(e)}
@@ -335,6 +339,7 @@ def archive_old_files(keep_recent: int, archive_path: str = 'memory_pool_archive
shutil.move(str(file_path), str(dest))
archived_count += 1
except Exception as e:
logger.warning(f"[pool_processor] Failed to archive {file_path.name}: {e}")
errors.append(f"{file_path.name}: {e}")
result = {
@@ -464,8 +469,8 @@ def get_pool_status() -> dict:
if collection_name in [c.name for c in client.list_collections()]:
collection = client.get_collection(name=collection_name)
collection_count = collection.count()
except Exception:
pass
except Exception as e:
logger.warning(f"[pool_processor] Failed to get collection count: {e}")
return {
'enabled': config.get('enabled', False),
@@ -17,6 +17,8 @@ from datetime import datetime
from pathlib import Path
from typing import Any, Dict
from aipass.prax import logger
_BRANCH_ROOT = Path(__file__).resolve().parents[3]
_BRANCH_NAME = _BRANCH_ROOT.name
JSON_DIR = _BRANCH_ROOT / f"{_BRANCH_NAME}_json"
@@ -27,6 +29,7 @@ def read_json(file_path: Path) -> dict | None:
try:
return json.loads(file_path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, FileNotFoundError):
logger.info(f"[json_handler] Could not read JSON from {file_path}")
return None
@@ -36,7 +39,8 @@ def write_json(file_path: Path, data: Any, indent: int = 2) -> bool:
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(json.dumps(data, indent=indent) + "\n", encoding="utf-8")
return True
except OSError:
except OSError as e:
logger.warning(f"[json_handler] Failed to write JSON to {file_path}: {e}")
return False
@@ -75,6 +79,7 @@ def log_operation(operation: str, data: Dict[str, Any] | None = None, module_nam
try:
log = json.loads(log_path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
logger.info(f"[json_handler] Could not read operation log {log_path}, starting fresh")
log = []
entry: Dict[str, Any] = {
@@ -93,5 +98,6 @@ def log_operation(operation: str, data: Dict[str, Any] | None = None, module_nam
try:
log_path.write_text(json.dumps(log, indent=2) + "\n", encoding="utf-8")
return True
except OSError:
except OSError as e:
logger.warning(f"[json_handler] Failed to write operation log to {log_path}: {e}")
return False
@@ -85,18 +85,21 @@ def read_memory_file(file_path: Path) -> Dict[str, Any]:
}
except json.JSONDecodeError as e:
logger.warning(f"[memory_files] Corrupt JSON in {file_path.name}: {e}")
return {
'success': False,
'error': f"Corrupt JSON in {file_path.name}: {e}"
}
except PermissionError:
logger.warning(f"[memory_files] Permission denied reading {file_path.name}")
return {
'success': False,
'error': f"Permission denied reading {file_path.name}"
}
except Exception as e:
logger.warning(f"[memory_files] Failed to read {file_path.name}: {e}")
return {
'success': False,
'error': f"Failed to read {file_path.name}: {e}"
@@ -161,16 +164,19 @@ def write_memory_file(file_path: Path, data: Dict[str, Any]) -> Dict[str, Any]:
except Exception as e:
# Clean up temp file on failure
logger.error(f"[memory_files] Write failed for {file_path.name}, cleaning up temp file: {e}")
Path(temp_path).unlink(missing_ok=True)
raise e
except PermissionError:
logger.warning(f"[memory_files] Permission denied writing {file_path.name}")
return {
'success': False,
'error': f"Permission denied writing {file_path.name}"
}
except Exception as e:
logger.warning(f"[memory_files] Failed to write {file_path.name}: {e}")
return {
'success': False,
'error': f"Failed to write {file_path.name}: {e}"
@@ -119,7 +119,8 @@ def get_entry_age(value: str) -> int:
entry_date = datetime.strptime(timestamp, "%Y-%m-%d")
age = (datetime.now() - entry_date).days
return max(0, age)
except ValueError:
except ValueError as e:
logger.warning(f"[learnings_manager] Failed to parse entry timestamp: {e}")
return 999999
@@ -346,6 +347,7 @@ def _vectorize_learnings(
return {'success': False, 'error': 'No embeddings generated'}
except Exception as e:
logger.warning(f"[learnings_manager] Embedding error for key_learnings: {e}")
return {'success': False, 'error': f"Embedding error: {e}"}
# Store in ChromaDB via subprocess
@@ -379,10 +381,13 @@ def _vectorize_learnings(
return json.loads(result.stdout)
except subprocess.TimeoutExpired:
logger.warning("[learnings_manager] Key learnings vectorization timed out")
return {'success': False, 'error': 'Vectorization timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[learnings_manager] Invalid JSON from key_learnings vectorization: {e}")
return {'success': False, 'error': f'Invalid JSON response: {e}'}
except Exception as e:
logger.warning(f"[learnings_manager] Key learnings vectorization error: {e}")
return {'success': False, 'error': str(e)}
@@ -433,6 +438,7 @@ def _vectorize_completed_tasks(
return {'success': False, 'error': 'No embeddings generated'}
except Exception as e:
logger.warning(f"[learnings_manager] Embedding error for recently_completed: {e}")
return {'success': False, 'error': f"Embedding error: {e}"}
# Store in ChromaDB via subprocess
@@ -466,10 +472,13 @@ def _vectorize_completed_tasks(
return json.loads(result.stdout)
except subprocess.TimeoutExpired:
logger.warning("[learnings_manager] Completed tasks vectorization timed out")
return {'success': False, 'error': 'Vectorization timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[learnings_manager] Invalid JSON from completed tasks vectorization: {e}")
return {'success': False, 'error': f'Invalid JSON response: {e}'}
except Exception as e:
logger.warning(f"[learnings_manager] Completed tasks vectorization error: {e}")
return {'success': False, 'error': str(e)}
@@ -497,6 +506,7 @@ def ensure_timestamps(file_path: Path) -> Dict[str, Any]:
if data is None:
return {'success': False, 'error': f'Failed to parse file: {file_path.name}'}
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read file: {e}")
return {'success': False, 'error': f'Failed to read file: {e}'}
learnings = _get_learnings(data)
@@ -517,6 +527,7 @@ def ensure_timestamps(file_path: Path) -> Dict[str, Any]:
try:
write_memory_file_simple(file_path, data)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to write file: {e}")
return {'success': False, 'error': f'Failed to write file: {e}'}
return {
@@ -549,6 +560,7 @@ def enforce_limit(file_path: Path) -> Dict[str, Any]:
if data is None:
return {'success': False, 'error': f'Failed to parse file: {file_path.name}'}
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read file: {e}")
return {'success': False, 'error': f'Failed to read file: {e}'}
learnings = _get_learnings(data)
@@ -595,6 +607,7 @@ def enforce_limit(file_path: Path) -> Dict[str, Any]:
try:
write_memory_file_simple(file_path, data)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to write file: {e}")
return {'success': False, 'error': f'Failed to write file: {e}'}
json_handler.log_operation("enforce_limit", {"removed": to_remove_count, "remaining": len(to_keep), "success": True})
@@ -633,6 +646,7 @@ def ensure_timestamps_completed(file_path: Path) -> Dict[str, Any]:
if data is None:
return {'success': False, 'error': f'Failed to parse file: {file_path.name}'}
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read file: {e}")
return {'success': False, 'error': f'Failed to read file: {e}'}
completed = _get_recently_completed(data)
@@ -656,6 +670,7 @@ def ensure_timestamps_completed(file_path: Path) -> Dict[str, Any]:
try:
write_memory_file_simple(file_path, data)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to write file: {e}")
return {'success': False, 'error': f'Failed to write file: {e}'}
return {
@@ -688,6 +703,7 @@ def enforce_limit_completed(file_path: Path) -> Dict[str, Any]:
if data is None:
return {'success': False, 'error': f'Failed to parse file: {file_path.name}'}
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read file: {e}")
return {'success': False, 'error': f'Failed to read file: {e}'}
completed = _get_recently_completed(data)
@@ -732,6 +748,7 @@ def enforce_limit_completed(file_path: Path) -> Dict[str, Any]:
try:
write_memory_file_simple(file_path, data)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to write file: {e}")
return {'success': False, 'error': f'Failed to write file: {e}'}
return {
@@ -770,6 +787,7 @@ def add_learning(
if data is None:
return {'success': False, 'error': f'Failed to parse file: {file_path.name}'}
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read file: {e}")
return {'success': False, 'error': f'Failed to read file: {e}'}
# Get existing learnings or create empty dict
@@ -786,6 +804,7 @@ def add_learning(
try:
write_memory_file_simple(file_path, data)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to write file: {e}")
return {'success': False, 'error': f'Failed to write file: {e}'}
# Enforce limit after adding
@@ -826,6 +845,7 @@ def update_status_counts(file_path: Path) -> Dict[str, Any]:
if data is None:
return {'success': False, 'error': f'Failed to parse file: {file_path.name}'}
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read file: {e}")
return {'success': False, 'error': f'Failed to read file: {e}'}
# Get actual counts
@@ -854,6 +874,7 @@ def update_status_counts(file_path: Path) -> Dict[str, Any]:
try:
write_memory_file_simple(file_path, data)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to write file: {e}")
return {'success': False, 'error': f'Failed to write file: {e}'}
return {
@@ -961,6 +982,7 @@ def process_all_branches() -> Dict[str, Any]:
with open(registry_path, 'r', encoding='utf-8') as f:
registry = json.load(f)
except Exception as e:
logger.warning(f"[learnings_manager] Failed to read registry: {e}")
return {'success': False, 'error': f'Failed to read registry: {e}'}
branches = registry.get('branches', [])
@@ -100,7 +100,8 @@ def _read_registry() -> List[Dict[str, Any]]:
branch['path'] = str(resolved)
return branches
except Exception:
except Exception as e:
logger.warning(f"[detector] Failed to read registry: {e}")
return []
@@ -148,7 +149,8 @@ def _load_config() -> Dict[str, Any]:
try:
with open(config_path, 'r', encoding='utf-8') as f:
return json.load(f)
except Exception:
except Exception as e:
logger.warning(f"[detector] Failed to load config: {e}")
return {}
@@ -169,8 +171,8 @@ def _count_file_lines(file_path: Path) -> int:
try:
with open(file_path, 'r', encoding='utf-8') as f:
return len(f.readlines())
except Exception:
# Silent failure - handlers don't log (3-tier architecture)
except Exception as e:
logger.warning(f"[detector] Failed to count lines in {file_path}: {e}")
return 0
@@ -194,8 +196,8 @@ def _get_max_lines(file_path: Path, branch_name: str | None = None) -> int:
file_limit = limits.get('max_lines')
if file_limit is not None:
return file_limit
except Exception:
pass
except Exception as e:
logger.warning(f"[detector] Failed to read file-level max_lines from {file_path}: {e}")
# 2. Try branch-level config (if branch_name provided or can be extracted)
if branch_name is None:
@@ -240,8 +242,9 @@ def _should_rollover(file_path: Path) -> tuple[bool, int, int, str, str]:
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception:
except Exception as e:
# Can't parse — fall back to line-based with hardcoded default
logger.warning(f"[detector] Failed to parse {file_path} for rollover check: {e}")
return (current_lines >= 600, current_lines, 600, '1.0.0', '')
metadata = data.get('document_metadata', {})
@@ -30,6 +30,9 @@ if TYPE_CHECKING:
from watchdog.observers import Observer as _ObserverType
from watchdog.events import FileSystemEventHandler as _HandlerType
# Temporary logger for module-level import guards (overwritten below by get_system_logger)
logger = logging.getLogger(__name__)
try:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
@@ -38,6 +41,7 @@ except ImportError:
WATCHDOG_AVAILABLE = False
Observer = None
FileSystemEventHandler = object # type: ignore[assignment,misc]
logger.info("Optional dependency 'watchdog' not available")
# Handler imports (relative within package)
from aipass.memory.apps.handlers.tracking.line_counter import update_line_count
@@ -95,8 +99,8 @@ def _get_rollover_threshold(branch_name: str, file_path: Path | None = None) ->
file_limit = metadata.get('limits', {}).get('max_lines')
if file_limit is not None:
return file_limit
except Exception:
pass
except Exception as e:
logger.warning(f"[memory_watcher] Failed to read file-level threshold from {file_path}: {e}")
# 2. Check per-branch config override
config_path = _MEMORY_ROOT / "config" / "memory_bank.config.json"
@@ -114,8 +118,8 @@ def _get_rollover_threshold(branch_name: str, file_path: Path | None = None) ->
if default_limit is not None:
return default_limit
except Exception:
pass
except Exception as e:
logger.warning(f"[memory_watcher] Failed to read rollover config: {e}")
# 4. Final fallback
return 600
@@ -191,8 +195,8 @@ def check_and_rollover() -> Dict[str, Any]:
lines_synced += 1
# Re-read actual line count after metadata update
line_count = len(memory_file.read_text(encoding='utf-8').splitlines())
except Exception:
pass # Non-critical - sync is best-effort
except Exception as e:
logger.warning(f"[memory_watcher] Non-critical metadata sync failed for {memory_file}: {e}")
if line_count > threshold:
results['files_over_limit'].append({
@@ -200,8 +204,8 @@ def check_and_rollover() -> Dict[str, Any]:
'lines': line_count,
'threshold': threshold
})
except Exception:
pass # Skip files we can't read
except Exception as e:
logger.warning(f"[memory_watcher] Failed to read memory file {memory_file}: {e}")
results['lines_synced'] = lines_synced
@@ -215,6 +219,7 @@ def check_and_rollover() -> Dict[str, Any]:
except ImportError:
logger.warning("Rollover handler not available")
except Exception as e:
logger.error(f"[memory_watcher] Rollover execution failed: {e}")
results['rollover_error'] = str(e)
results['success'] = False
@@ -252,7 +257,8 @@ def _check_memory_pool() -> Dict[str, Any]:
with open(config_path) as f:
config = json.load(f)
pool_config = config.get('memory_pool', {})
except Exception:
except Exception as exc:
logger.warning(f"[memory_watcher] Could not load memory pool config: {exc}")
return {'success': False, 'error': 'Could not load config'}
# Check if enabled
@@ -290,6 +296,7 @@ def _check_memory_pool() -> Dict[str, Any]:
'action': 'processed'
}
except Exception as e:
logger.warning(f"[memory_watcher] Memory pool processing failed: {e}")
return {'success': False, 'error': str(e), 'action': 'failed'}
@@ -313,7 +320,8 @@ def _check_plans() -> Dict[str, Any]:
with open(config_path, 'r', encoding='utf-8') as f:
config = json.load(f)
plans_config = config.get('plans', {})
except Exception:
except Exception as exc:
logger.warning(f"[memory_watcher] Could not load plans config: {exc}")
return {'success': False, 'error': 'Could not load config'}
# Check if enabled
@@ -344,8 +352,8 @@ def _check_plans() -> Dict[str, Any]:
if manifest_path.exists():
try:
manifest = json.loads(manifest_path.read_text(encoding='utf-8'))
except Exception:
pass
except Exception as e:
logger.warning(f"[memory_watcher] Failed to read plans manifest: {e}")
pending = [f for f in files if f.name not in manifest]
pending_count = len(pending)
@@ -367,6 +375,7 @@ def _check_code_archive() -> Dict[str, Any]:
from aipass.memory.apps.handlers.archive.indexer import check_for_new_files
return check_for_new_files()
except Exception as e:
logger.warning(f"[memory_watcher] Code archive check failed: {e}")
return {'success': False, 'error': str(e)}
@@ -415,7 +424,8 @@ def _get_branch_paths() -> list[Path]:
paths.append(branch_path)
return paths
except Exception:
except Exception as e:
logger.warning(f"[memory_watcher] Failed to read branch paths from registry: {e}")
return []
@@ -546,8 +556,8 @@ def start_memory_watcher() -> Dict[str, Any]:
try:
new_observer.schedule(watcher, str(branch_path), recursive=False)
watched_paths.append(str(branch_path))
except Exception:
pass # Skip invalid paths silently
except Exception as e:
logger.warning(f"[memory_watcher] Failed to schedule watcher for {branch_path}: {e}")
# Start observer
new_observer.start()
@@ -652,6 +662,7 @@ if __name__ == "__main__":
while True:
time.sleep(1)
except KeyboardInterrupt:
logger.info("[memory_watcher] Watcher stopped by user (KeyboardInterrupt)")
print("\nStopping...")
stop_memory_watcher()
else:
@@ -78,6 +78,7 @@ def create_rollover_backup(file_path: Path) -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[extractor] Backup failed for {file_path}: {e}")
return {
'success': False,
'error': f'Backup failed: {e}'
@@ -116,6 +117,7 @@ def restore_from_backup(file_path: Path) -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[extractor] Restore from backup failed for {file_path}: {e}")
return {
'success': False,
'error': f'Restore failed: {e}'
@@ -328,6 +330,7 @@ def _extract_items_v2(file_path: Path, data: Dict[str, Any]) -> Dict[str, Any]:
_write_memory_file(file_path, data)
new_lines = _count_file_lines(file_path)
except Exception as e:
logger.error(f"[extractor] Failed to write file after v2 extraction: {e}")
return {
'success': False,
'error': f"Failed to write file: {e}"
@@ -388,6 +391,7 @@ def extract_items(
}
current_lines = _count_file_lines(file_path)
except Exception as e:
logger.warning(f"[extractor] Failed to read file {file_path}: {e}")
return {
'success': False,
'error': f"Failed to read file: {e}"
@@ -445,6 +449,7 @@ def extract_items(
_write_memory_file(file_path, data)
new_line_count = _count_file_lines(file_path)
except Exception as e:
logger.error(f"[extractor] Failed to write file after v1 extraction: {e}")
return {
'success': False,
'error': f"Failed to write file: {e}"
@@ -124,10 +124,13 @@ def store_vectors_subprocess(branch: str, memory_type: str, embeddings: list,
return json.loads(result.stdout)
except subprocess.TimeoutExpired:
logger.warning("[orchestrator] Vector storage operation timed out")
return {'success': False, 'error': 'Storage operation timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[orchestrator] Invalid JSON from storage subprocess: {e}")
return {'success': False, 'error': f'Invalid JSON response: {e}'}
except Exception as e:
logger.warning(f"[orchestrator] Vector storage subprocess error: {e}")
return {'success': False, 'error': str(e)}
@@ -161,10 +164,13 @@ def encode_batch_subprocess(texts: list) -> dict:
return json.loads(result.stdout)
except subprocess.TimeoutExpired:
logger.warning("[orchestrator] Embedding subprocess timed out")
return {'success': False, 'error': 'Embedding timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[orchestrator] Invalid JSON from embedding subprocess: {e}")
return {'success': False, 'error': f'Invalid JSON from embedder: {e}'}
except Exception as e:
logger.warning(f"[orchestrator] Embedding subprocess error: {e}")
return {'success': False, 'error': str(e)}
@@ -469,8 +475,8 @@ def execute_rollover() -> Dict[str, Any]:
success_count=success_count,
failed_count=len(failed))
logger.info("[rollover] Fired rollover_complete event")
except Exception:
pass # Trigger system optional
except Exception as e:
logger.warning(f"[orchestrator] Failed to fire rollover_complete event: {e}")
# Post-rollover: update central stats
try:
@@ -51,6 +51,7 @@ def normalize_memory_file(file_path: Path, dry_run: bool = False) -> Dict[str, A
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception as e:
logger.warning(f"[normalize] Failed to read {file_path}: {e}")
return {'success': False, 'error': f"Failed to read: {e}"}
changes = []
@@ -109,8 +110,8 @@ def normalize_memory_file(file_path: Path, dry_run: bool = False) -> Dict[str, A
with open(file_path, 'r', encoding='utf-8') as f:
metadata['status']['current_lines'] = len(f.readlines())
changes.append("Added current_lines count")
except Exception:
pass
except Exception as e:
logger.warning(f"[normalize] Failed to count lines in {file_path}: {e}")
if 'last_health_check' not in metadata['status']:
metadata['status']['last_health_check'] = datetime.now().strftime("%Y-%m-%d")
@@ -123,6 +124,7 @@ def normalize_memory_file(file_path: Path, dry_run: bool = False) -> Dict[str, A
json.dump(data, f, indent=2, ensure_ascii=False)
f.write('\n')
except Exception as e:
logger.error(f"[normalize] Failed to write {file_path}: {e}")
return {'success': False, 'error': f"Failed to write: {e}"}
json_handler.log_operation("normalize_memory_file", {"file": file_path.name, "changes": len(changes), "success": True})
@@ -156,6 +158,7 @@ def normalize_all_memory_files(dry_run: bool = False) -> Dict[str, Any]:
registry = json.load(f)
branches = registry.get('branches', [])
except Exception as e:
logger.warning(f"[normalize] Failed to read registry: {e}")
return {'success': False, 'error': f"Failed to read registry: {e}"}
results = {
@@ -96,10 +96,13 @@ def encode_query_subprocess(query: str) -> dict:
'dimension': data.get('dimension', 384)
}
except subprocess.TimeoutExpired:
logger.warning("[query_executor] Embedding subprocess timed out")
return {'success': False, 'error': 'Embedding timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[query_executor] Invalid JSON from embedder: {e}")
return {'success': False, 'error': f'Invalid JSON from embedder: {e}'}
except Exception as e:
logger.error(f"[query_executor] Embedding subprocess failed: {e}")
return {'success': False, 'error': str(e)}
@@ -150,10 +153,13 @@ def search_vectors_subprocess(
return json.loads(result.stdout)
except subprocess.TimeoutExpired:
logger.warning("[query_executor] Search subprocess timed out")
return {'success': False, 'error': 'Search operation timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[query_executor] Invalid JSON from search subprocess: {e}")
return {'success': False, 'error': f'Invalid JSON response: {e}'}
except Exception as e:
logger.error(f"[query_executor] Search subprocess failed: {e}")
return {'success': False, 'error': str(e)}
@@ -71,6 +71,7 @@ class QueryEncoder:
import torch
from sentence_transformers import SentenceTransformer
except ImportError as e:
logger.info(f"[vector_search] Optional ML dependencies not available: {e}")
raise ImportError(
f"Search requires sentence-transformers and torch. "
f"Install with: pip install sentence-transformers torch. "
@@ -183,6 +184,7 @@ class SearchService:
embedding_function=None
)
except Exception as e:
logger.warning(f"[vector_search] Collection lookup failed for '{collection_name}': {e}")
return {
"collection": collection_name,
"exists": False,
@@ -325,6 +327,7 @@ def search_collection(
}
except Exception as e:
logger.error(f"[vector_search] Collection search failed for '{collection_name}': {e}")
return {
'success': False,
'error': f"Search failed: {e}"
@@ -368,6 +371,7 @@ def encode_query(query: str) -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[vector_search] Query encoding failed: {e}")
return {
'success': False,
'error': f"Encoding failed: {e}"
@@ -406,6 +410,7 @@ def list_collections(db_path: Path | None = None) -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[vector_search] Failed to list collections: {e}")
return {
'success': False,
'error': f"Failed to list collections: {e}"
@@ -497,6 +502,7 @@ def search_all_collections(
}
except Exception as e:
logger.error(f"[vector_search] Multi-collection search failed: {e}")
return {
'success': False,
'error': f"Multi-collection search failed: {e}"
@@ -63,6 +63,7 @@ def get_client(db_path: Path):
try:
import chromadb
except ImportError:
logger.info("[chroma] chromadb not installed, vector storage unavailable")
raise ImportError(
"chromadb is required for vector storage. "
"Install with: pip install chromadb"
@@ -202,7 +203,8 @@ class ChromaService:
"exists": True,
"vector_count": count
}
except Exception:
except Exception as e:
logger.warning(f"[chroma] Collection stats lookup failed for '{collection_name}': {e}")
return {
"collection": collection_name,
"exists": False,
@@ -323,6 +325,7 @@ def store_vectors(
}
except Exception as e:
logger.error(f"[chroma] Vector storage failed: {e}")
return {
'success': False,
'error': f"Storage failed: {e}"
@@ -350,6 +353,7 @@ def get_collection_stats(branch: str, memory_type: str) -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[chroma] Failed to get collection stats: {e}")
return {
'success': False,
'error': f"Failed to get stats: {e}"
@@ -374,6 +378,7 @@ def list_all_collections() -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[chroma] Failed to list collections: {e}")
return {
'success': False,
'error': f"Failed to list collections: {e}"
@@ -399,6 +404,7 @@ def get_database_info() -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[chroma] Failed to get database info: {e}")
return {
'success': False,
'error': f"Failed to get database info: {e}"
@@ -489,6 +495,7 @@ def search_vectors(
except Exception as e:
# Collection might not exist - skip it
logger.warning(f"[chroma] Skipping collection '{collection_name}' during search: {e}")
continue
# Sort by distance (lower is better)
@@ -503,6 +510,7 @@ def search_vectors(
}
except Exception as e:
logger.error(f"[chroma] Vector search failed: {e}")
return {
'success': False,
'error': f"Search failed: {e}"
@@ -20,9 +20,12 @@ Output: JSON on stdout with result
import sys
import json
import logging
from pathlib import Path
from datetime import datetime
logger = logging.getLogger(__name__)
# =============================================================================
# CHROMADB OPERATIONS (inline — no aipass imports)
@@ -122,7 +125,8 @@ def _check_plan(plan_label, db_path=None):
collection_name = "flow_flow_plans"
try:
collection = client.get_collection(collection_name, embedding_function=None)
except Exception:
except Exception as e:
logger.warning(f"[chroma_subprocess] Collection '{collection_name}' not found during plan check: {e}")
return {
'success': True,
'found': False,
@@ -185,7 +189,8 @@ def _search_vectors(query_embedding, branch=None, memory_type=None, n_results=5,
'distance': results['distances'][0][i] if results['distances'] else None,
'id': results['ids'][0][i] if results['ids'] else None
})
except Exception:
except Exception as e:
logger.warning(f"[chroma_subprocess] Skipping collection '{cname}' during search: {e}")
continue
all_results.sort(key=lambda x: x['distance'] if x['distance'] is not None else float('inf'))
@@ -240,6 +245,7 @@ def main():
print(json.dumps(result))
except Exception as e:
logger.error(f"[chroma_subprocess] Subprocess operation failed: {e}")
print(json.dumps({'success': False, 'error': str(e)}))
sys.exit(1)
@@ -25,6 +25,7 @@ Key Functions:
from typing import Dict, Any
from pathlib import Path
from aipass.prax import logger
from aipass.memory.apps.handlers.json import json_handler
@@ -128,6 +129,7 @@ def get_collection(
}
except Exception as e:
logger.error(f"[chroma_client] Failed to get collection '{collection_name}': {e}")
return {
'success': False,
'error': str(e)
@@ -24,6 +24,7 @@ import re
from typing import Dict, List, Any, Optional
from pathlib import Path
from aipass.prax import logger
from aipass.memory.apps.handlers.json import json_handler
# memory/ root resolved from symbolic/deduplicator.py
@@ -153,7 +154,8 @@ def deduplicate_fragment(
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read().decode("utf-8"))
content = result.get("choices", [{}])[0].get("message", {}).get("content", "")
except (urllib.error.URLError, json.JSONDecodeError, KeyError, IndexError):
except (urllib.error.URLError, json.JSONDecodeError, KeyError, IndexError) as e:
logger.warning(f"[deduplicator] LLM dedup request failed, defaulting to ADD: {e}")
return {
'success': True,
'action': 'ADD',
@@ -320,7 +322,8 @@ def _parse_dedup_response(raw_text: str) -> Optional[Dict[str, Any]]:
result = json.loads(text)
if isinstance(result, dict) and _validate_dedup_result(result):
return result
except (json.JSONDecodeError, ValueError):
except (json.JSONDecodeError, ValueError) as e:
logger.warning(f"[deduplicator] Direct JSON parse failed, trying fallback: {e}")
pass
# Attempt 2: Strip markdown fences
@@ -330,7 +333,8 @@ def _parse_dedup_response(raw_text: str) -> Optional[Dict[str, Any]]:
result = json.loads(match.group(1).strip())
if isinstance(result, dict) and _validate_dedup_result(result):
return result
except (json.JSONDecodeError, ValueError):
except (json.JSONDecodeError, ValueError) as e:
logger.warning(f"[deduplicator] Markdown-fenced JSON parse failed, trying fallback: {e}")
pass
# Attempt 3: Find JSON object in text
@@ -340,7 +344,8 @@ def _parse_dedup_response(raw_text: str) -> Optional[Dict[str, Any]]:
result = json.loads(match.group(0))
if isinstance(result, dict) and _validate_dedup_result(result):
return result
except (json.JSONDecodeError, ValueError):
except (json.JSONDecodeError, ValueError) as e:
logger.warning(f"[deduplicator] Regex-extracted JSON parse failed: {e}")
pass
return None
@@ -22,6 +22,7 @@ from datetime import datetime
from pathlib import Path
from typing import Dict, List, Any, Optional
from aipass.prax import logger
from aipass.memory.apps.handlers.json import json_handler
# memory/ root resolved from symbolic/extractor.py
@@ -308,7 +309,8 @@ def _parse_llm_json(raw_text: str) -> Optional[List[Dict[str, Any]]]:
result = json.loads(text)
if isinstance(result, list):
return result
except (json.JSONDecodeError, ValueError):
except (json.JSONDecodeError, ValueError) as e:
logger.warning(f"[extractor] Direct JSON parse failed, trying fallback: {e}")
pass
# Attempt 2: Strip markdown fences
match = re.search(r'```(?:json)?\s*\n?(.*?)\n?\s*```', text, re.DOTALL)
@@ -317,7 +319,8 @@ def _parse_llm_json(raw_text: str) -> Optional[List[Dict[str, Any]]]:
result = json.loads(match.group(1).strip())
if isinstance(result, list):
return result
except (json.JSONDecodeError, ValueError):
except (json.JSONDecodeError, ValueError) as e:
logger.warning(f"[extractor] Markdown-fenced JSON parse failed: {e}")
pass
return None
@@ -408,7 +411,7 @@ def extract_fragments_llm(chat_history: List[Dict[str, Any]]) -> Dict[str, Any]:
except (urllib.error.URLError, json.JSONDecodeError, KeyError, IndexError) as e:
err_msg = f"Chunk {i+1}/{len(chunks)}: {type(e).__name__}: {e}"
chunk_errors.append(err_msg)
# Error tracked in chunk_errors for module-layer logging
logger.warning(f"[extractor] LLM extraction failed for chunk {i+1}/{len(chunks)}: {e}")
continue
if not content:
continue
@@ -24,6 +24,8 @@ Key Functions:
from typing import Dict, List, Any
from pathlib import Path
from aipass.prax import logger
# Handler imports (domain-organized, no modules)
from aipass.memory.apps.handlers.vector import embedder
from aipass.memory.apps.handlers.symbolic.chroma_client import get_chroma_client
@@ -95,7 +97,8 @@ def search_by_vector(
COLLECTION_NAME,
embedding_function=None
)
except Exception:
except Exception as e:
logger.warning(f"[retriever] Collection '{COLLECTION_NAME}' not found for vector search: {e}")
return {
'success': True,
'results': [],
@@ -119,6 +122,7 @@ def search_by_vector(
}
except Exception as e:
logger.error(f"[retriever] Vector search failed: {e}")
return {
'success': False,
'error': f"Vector search failed: {e}"
@@ -163,7 +167,8 @@ def search_by_dimensions(
COLLECTION_NAME,
embedding_function=None
)
except Exception:
except Exception as e:
logger.warning(f"[retriever] Collection '{COLLECTION_NAME}' not found for dimension search: {e}")
return {
'success': True,
'results': [],
@@ -200,6 +205,7 @@ def search_by_dimensions(
}
except Exception as e:
logger.error(f"[retriever] Dimension search failed: {e}")
return {
'success': False,
'error': f"Dimension search failed: {e}"
@@ -245,7 +251,8 @@ def search_by_triggers(
COLLECTION_NAME,
embedding_function=None
)
except Exception:
except Exception as e:
logger.warning(f"[retriever] Collection '{COLLECTION_NAME}' not found for trigger search: {e}")
return {
'success': True,
'results': [],
@@ -300,6 +307,7 @@ def search_by_triggers(
}
except Exception as e:
logger.error(f"[retriever] Trigger search failed: {e}")
return {
'success': False,
'error': f"Trigger search failed: {e}"
@@ -32,6 +32,7 @@ from pathlib import Path
# Handler imports (domain-organized, no modules)
from aipass.memory.apps.handlers.vector import embedder
from aipass.memory.apps.handlers.json import json_handler
from aipass.prax import logger
# =============================================================================
@@ -308,6 +309,7 @@ def store_fragment(
}
except Exception as e:
logger.error(f"[storage] Fragment storage failed: {e}")
return {
'success': False,
'error': f"Storage failed: {e}"
@@ -420,6 +422,7 @@ def store_fragments_batch(
}
except Exception as e:
logger.error(f"[storage] Batch fragment storage failed: {e}")
return {
'success': False,
'error': f"Batch storage failed: {e}"
@@ -540,6 +543,7 @@ def store_llm_fragment(
}
except Exception as e:
logger.error(f"[storage] LLM fragment storage failed: {e}")
return {
'success': False,
'error': f"LLM fragment storage failed: {e}"
@@ -668,6 +672,7 @@ def store_llm_fragments_batch(
}
except Exception as e:
logger.error(f"[storage] Batch LLM fragment storage failed: {e}")
return {
'success': False,
'error': f"Batch LLM fragment storage failed: {e}"
@@ -712,6 +717,7 @@ def delete_fragment(
}
except Exception as e:
logger.error(f"[storage] Fragment deletion failed: {e}")
return {
'success': False,
'error': f"Fragment deletion failed: {e}"
@@ -223,6 +223,7 @@ def diff_template_vs_branch(branch_path: str | Path) -> dict:
with open(path, 'r', encoding='utf-8') as f:
templates[name] = json.load(f)
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"[differ] Failed to load template {path.name}: {e}")
result["errors"].append(f"Failed to load template {path.name}: {e}")
return result
@@ -241,6 +242,7 @@ def diff_template_vs_branch(branch_path: str | Path) -> dict:
with open(f, 'r', encoding='utf-8') as fh:
current = json.load(fh)
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"[differ] Failed to read {f.name}: {e}")
result["errors"].append(f"Failed to read {f.name}: {e}")
continue
@@ -279,6 +281,7 @@ def diff_template_vs_branch(branch_path: str | Path) -> dict:
with open(f, 'r', encoding='utf-8') as fh:
current = json.load(fh)
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"[differ] Failed to read {f.name}: {e}")
result["errors"].append(f"Failed to read {f.name}: {e}")
continue
@@ -292,7 +292,8 @@ def _load_registry() -> Optional[List[Dict[str, Any]]]:
resolved = _REPO_ROOT / raw_path
branch['path'] = str(resolved)
return [b for b in branches if b.get("status") == "active"]
except (json.JSONDecodeError, KeyError):
except (json.JSONDecodeError, KeyError) as e:
logger.warning(f"[pusher] Failed to load registry {REGISTRY_PATH}: {e}")
return None
@@ -326,7 +327,8 @@ def _load_templates() -> Optional[Dict[str, dict]]:
try:
with open(path, 'r', encoding='utf-8') as f:
templates[name] = json.load(f)
except (json.JSONDecodeError, IOError):
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"[pusher] Failed to load template {path}: {e}")
return None
return templates
@@ -441,7 +443,8 @@ def _update_version_file(branches_pushed: List[str]) -> bool:
json.dump(version_data, f, indent=2, ensure_ascii=False)
f.write('\n')
return True
except Exception:
except Exception as e:
logger.warning(f"[pusher] Failed to update version file: {e}")
return False
@@ -463,7 +466,8 @@ def get_template_status() -> dict:
status["version"] = data.get("version")
status["last_push"] = data.get("last_push")
status["last_push_branches"] = data.get("last_push_branches", [])
except (json.JSONDecodeError, IOError):
except (json.JSONDecodeError, IOError) as e:
logger.warning(f"[pusher] Failed to read version file: {e}")
status["version"] = "error reading version file"
return status
@@ -101,7 +101,8 @@ def _read_json(path: Path) -> dict | None:
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except (json.JSONDecodeError, OSError):
except (json.JSONDecodeError, OSError) as e:
logger.warning(f"[spawn_pusher] Failed to read JSON {path}: {e}")
return None
@@ -112,7 +113,8 @@ def _write_json(path: Path, data: dict) -> bool:
json.dump(data, f, indent=2, ensure_ascii=False)
f.write("\n")
return True
except OSError:
except OSError as e:
logger.warning(f"[spawn_pusher] Failed to write JSON {path}: {e}")
return False
@@ -50,7 +50,8 @@ def _count_physical_lines(file_path: Path) -> int:
try:
with open(file_path, 'r', encoding='utf-8') as f:
return len(f.readlines())
except Exception:
except Exception as e:
logger.warning(f"[line_counter] Failed to count lines in {file_path}: {e}")
return 0
@@ -71,6 +71,7 @@ class EmbeddingService:
import torch
from sentence_transformers import SentenceTransformer
except ImportError as e:
logger.info(f"[embedder] Optional ML dependencies not available: {e}")
raise ImportError(
f"Embedding requires sentence-transformers and torch. "
f"Install with: pip install sentence-transformers torch. "
@@ -204,6 +205,7 @@ def encode_batch(texts: List[str]) -> Dict[str, Any]:
}
except Exception as e:
logger.error(f"[embedder] Batch encoding failed: {e}")
return {
'success': False,
'error': f"Encoding failed: {e}"
@@ -284,6 +286,7 @@ def get_model_info() -> Dict[str, Any]:
'gpu_enabled': service.use_gpu
}
except Exception as e:
logger.warning(f"[embedder] Failed to get model info: {e}")
return {
'success': False,
'error': f"Failed to get model info: {e}"
+1
View File
@@ -342,6 +342,7 @@ if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
logger.info("[memory] Operation cancelled by user (KeyboardInterrupt)")
console.print("\n\nOperation cancelled by user")
sys.exit(0)
except Exception as e:
@@ -255,6 +255,7 @@ def process_plans_command() -> None:
from ..handlers.intake.plans_processor import process_plans
result = process_plans()
except Exception as e:
logger.error(f"[rollover] Plan processing failed: {e}")
error(f"Plan processing failed: {e}")
return
+1
View File
@@ -97,6 +97,7 @@ def handle_command(command: str, args: List[str]) -> bool:
try:
n_results = int(args[i + 1])
except ValueError:
logger.warning(f"[search] Invalid --n argument: {args[i + 1]}")
error(f"Invalid number: {args[i + 1]}")
return True
i += 2
+11 -8
View File
@@ -169,8 +169,8 @@ def create_fragment(
trigger.fire('fragment_created',
fragment_id=result['fragment'].get('id'),
source_branch=source_branch or 'unknown')
except Exception:
pass # Trigger optional
except Exception as e:
logger.warning(f"[symbolic] Trigger fire for fragment_created failed: {e}")
return result
@@ -184,8 +184,8 @@ def store_fragment(
try:
from aipass.trigger.apps.modules.core import trigger
trigger.fire('fragment_stored', fragment_id=result.get('fragment_id'))
except Exception:
pass # Trigger optional
except Exception as e:
logger.warning(f"[symbolic] Trigger fire for fragment_stored failed: {e}")
return result
@@ -328,8 +328,8 @@ def extract_and_store_llm(
component="memory",
severity="high"
)
except Exception:
pass # Trigger unavailable — prax log is the fallback
except Exception as e:
logger.warning(f"[symbolic] Error report trigger unavailable: {e}")
return {
'success': False,
'processed': 0,
@@ -418,6 +418,7 @@ def extract_and_store_llm(
skipped += 1
except Exception as e:
logger.error(f"[symbolic] Fragment processing error: {e}")
errors.append(f"Fragment processing error: {e}")
total_processed = added + updated + skipped
@@ -1004,6 +1005,7 @@ def search_fragments_cli(args: List[str]) -> None:
try:
n_results = int(args[i + 1])
except ValueError:
logger.warning(f"[symbolic] Invalid --n argument: {args[i + 1]}")
console.print(f"[red]Error:[/red] Invalid number: {args[i + 1]}")
return
i += 2
@@ -1408,6 +1410,7 @@ def _parse_jsonl_to_chat_history(jsonl_path: Path) -> List[Dict[str, Any]]:
try:
entry = json.loads(line)
except json.JSONDecodeError:
logger.info("[symbolic] Skipping malformed JSONL line during bootstrap parse")
continue
msg_type = entry.get('type', '')
@@ -1638,8 +1641,8 @@ def bootstrap_from_jsonl(max_sessions: int = 8) -> None:
)
col = client.get_collection('symbolic_fragments')
console.print(f" [bold green]Collection total: {col.count()} fragments[/bold green]")
except Exception:
pass
except Exception as e:
logger.warning(f"[symbolic] Failed to read ChromaDB collection count: {e}")
console.print()
logger.info(
+4
View File
@@ -23,6 +23,7 @@ import sys
from pathlib import Path
from typing import List
from aipass.prax import logger
from aipass.cli.apps.modules import console, error
from aipass.memory.apps.handlers.json import json_handler
@@ -127,10 +128,13 @@ def _check_plan_subprocess(plan_label: str) -> dict:
return json.loads(result.stdout)
except subprocess.TimeoutExpired:
logger.warning("[verify] Plan check subprocess timed out")
return {'success': False, 'error': 'Check operation timed out'}
except json.JSONDecodeError as e:
logger.warning(f"[verify] Invalid JSON from plan check subprocess: {e}")
return {'success': False, 'error': f'Invalid JSON response: {e}'}
except Exception as e:
logger.error(f"[verify] Plan check subprocess failed: {e}")
return {'success': False, 'error': str(e)}