diff --git a/src/config.py b/src/config.py index 2aa0d5d..c27b17c 100644 --- a/src/config.py +++ b/src/config.py @@ -393,7 +393,8 @@ def check_ollama_model_available(model_name: str) -> bool: model_name == m or model_name == m.split(":")[0] or m.startswith(model_name) for m in models ) - except Exception: + except Exception as exc: + _startup_logger.debug("Ollama model check failed: %s", exc) return False diff --git a/src/dashboard/app.py b/src/dashboard/app.py index 28360d2..a7555fc 100644 --- a/src/dashboard/app.py +++ b/src/dashboard/app.py @@ -510,7 +510,8 @@ async def swarm_live(websocket: WebSocket): while True: # Keep connection alive; events are pushed via ws_mgr.broadcast() await websocket.receive_text() - except Exception: + except Exception as exc: + logger.debug("WebSocket disconnect error: %s", exc) ws_mgr.disconnect(websocket) @@ -532,7 +533,8 @@ async def swarm_agents_sidebar(): f"" ) return "\n".join(lines) if lines else '
No agents configured
' - except Exception: + except Exception as exc: + logger.debug("Agents sidebar error: %s", exc) return '
Agents unavailable
' diff --git a/src/dashboard/middleware/csrf.py b/src/dashboard/middleware/csrf.py index e3a8320..d607e1f 100644 --- a/src/dashboard/middleware/csrf.py +++ b/src/dashboard/middleware/csrf.py @@ -5,6 +5,7 @@ to protect state-changing endpoints from cross-site request attacks. """ import hmac +import logging import secrets from collections.abc import Callable from functools import wraps @@ -16,6 +17,8 @@ from starlette.responses import JSONResponse, Response # Module-level set to track exempt routes _exempt_routes: set[str] = set() +logger = logging.getLogger(__name__) + def csrf_exempt(endpoint: Callable) -> Callable: """Decorator to mark an endpoint as exempt from CSRF validation. @@ -278,7 +281,8 @@ class CSRFMiddleware(BaseHTTPMiddleware): form_token = form_data.get(self.form_field) if form_token and validate_csrf_token(str(form_token), csrf_cookie): return True - except Exception: + except Exception as exc: + logger.debug("CSRF form parsing error: %s", exc) # Error parsing form data, treat as invalid pass diff --git a/src/dashboard/middleware/request_logging.py b/src/dashboard/middleware/request_logging.py index 1084d48..8d6e8f0 100644 --- a/src/dashboard/middleware/request_logging.py +++ b/src/dashboard/middleware/request_logging.py @@ -115,7 +115,8 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware): "duration_ms": f"{duration_ms:.0f}", }, ) - except Exception: + except Exception as exc: + logger.debug("Escalation logging error: %s", exc) pass # never let escalation break the request # Re-raise the exception diff --git a/src/dashboard/middleware/security_headers.py b/src/dashboard/middleware/security_headers.py index 9cd5015..c0ae043 100644 --- a/src/dashboard/middleware/security_headers.py +++ b/src/dashboard/middleware/security_headers.py @@ -4,10 +4,14 @@ Adds common security headers to all HTTP responses to improve application security posture against various attacks. """ +import logging + from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request from starlette.responses import Response +logger = logging.getLogger(__name__) + class SecurityHeadersMiddleware(BaseHTTPMiddleware): """Middleware to add security headers to all responses. @@ -130,12 +134,8 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware): """ try: response = await call_next(request) - except Exception: - import logging - - logging.getLogger(__name__).debug( - "Upstream error in security headers middleware", exc_info=True - ) + except Exception as exc: + logger.debug("Upstream error in security headers middleware: %s", exc) from starlette.responses import PlainTextResponse response = PlainTextResponse("Internal Server Error", status_code=500) diff --git a/src/dashboard/routes/agents.py b/src/dashboard/routes/agents.py index b7d34d1..6a758a9 100644 --- a/src/dashboard/routes/agents.py +++ b/src/dashboard/routes/agents.py @@ -220,7 +220,8 @@ async def reject_tool(request: Request, approval_id: str): # Resume so the agent knows the tool was rejected try: await continue_chat(pending["run_output"]) - except Exception: + except Exception as exc: + logger.warning("Agent tool rejection error: %s", exc) pass reject(approval_id) diff --git a/src/dashboard/routes/briefing.py b/src/dashboard/routes/briefing.py index 16bbfc2..c72a3a8 100644 --- a/src/dashboard/routes/briefing.py +++ b/src/dashboard/routes/briefing.py @@ -27,7 +27,8 @@ async def get_briefing(request: Request): """Return today's briefing page (generated or cached).""" try: briefing = briefing_engine.get_or_generate() - except Exception: + except Exception as exc: + logger.debug("Briefing generation failed: %s", exc) logger.exception("Briefing generation failed") now = datetime.now(UTC) briefing = Briefing( diff --git a/src/dashboard/routes/chat_api.py b/src/dashboard/routes/chat_api.py index 9b595d4..9e047a9 100644 --- a/src/dashboard/routes/chat_api.py +++ b/src/dashboard/routes/chat_api.py @@ -51,7 +51,8 @@ async def api_chat(request: Request): try: body = await request.json() - except Exception: + except Exception as exc: + logger.warning("Chat API JSON parse error: %s", exc) return JSONResponse(status_code=400, content={"error": "Invalid JSON"}) messages = body.get("messages") diff --git a/src/dashboard/routes/experiments.py b/src/dashboard/routes/experiments.py index 37b0be3..0b8b44e 100644 --- a/src/dashboard/routes/experiments.py +++ b/src/dashboard/routes/experiments.py @@ -30,8 +30,8 @@ async def experiments_page(request: Request): history = [] try: history = get_experiment_history(_workspace()) - except Exception: - logger.debug("Failed to load experiment history", exc_info=True) + except Exception as exc: + logger.debug("Failed to load experiment history: %s", exc) return templates.TemplateResponse( request, diff --git a/src/dashboard/routes/grok.py b/src/dashboard/routes/grok.py index b6757fe..4b44316 100644 --- a/src/dashboard/routes/grok.py +++ b/src/dashboard/routes/grok.py @@ -52,8 +52,8 @@ async def grok_status(request: Request): "estimated_cost_sats": backend.stats.estimated_cost_sats, "errors": backend.stats.errors, } - except Exception: - logger.debug("Failed to load Grok stats", exc_info=True) + except Exception as exc: + logger.warning("Failed to load Grok stats: %s", exc) return templates.TemplateResponse( request, @@ -94,8 +94,8 @@ async def toggle_grok_mode(request: Request): tool_name="grok_mode_toggle", success=True, ) - except Exception: - logger.debug("Failed to log Grok toggle to Spark", exc_info=True) + except Exception as exc: + logger.warning("Failed to log Grok toggle to Spark: %s", exc) return HTMLResponse( _render_toggle_card(_grok_mode_active), @@ -128,8 +128,8 @@ def _run_grok_query(message: str) -> dict: sats = min(settings.grok_max_sats_per_query, 100) ln.create_invoice(sats, f"Grok: {message[:50]}") invoice_note = f" | {sats} sats" - except Exception: - logger.debug("Lightning invoice creation failed", exc_info=True) + except Exception as exc: + logger.warning("Lightning invoice creation failed: %s", exc) try: result = backend.run(message) diff --git a/src/dashboard/routes/health.py b/src/dashboard/routes/health.py index d4670ed..b9455b5 100644 --- a/src/dashboard/routes/health.py +++ b/src/dashboard/routes/health.py @@ -76,8 +76,8 @@ def _check_ollama_sync() -> DependencyStatus: sovereignty_score=10, details={"url": settings.ollama_url, "model": settings.ollama_model}, ) - except Exception: - logger.debug("Ollama health check failed", exc_info=True) + except Exception as exc: + logger.debug("Ollama health check failed: %s", exc) return DependencyStatus( name="Ollama AI", @@ -101,7 +101,8 @@ async def _check_ollama() -> DependencyStatus: try: result = await asyncio.to_thread(_check_ollama_sync) - except Exception: + except Exception as exc: + logger.debug("Ollama async check failed: %s", exc) result = DependencyStatus( name="Ollama AI", status="unavailable", diff --git a/src/dashboard/routes/system.py b/src/dashboard/routes/system.py index 86ac817..7c22bb9 100644 --- a/src/dashboard/routes/system.py +++ b/src/dashboard/routes/system.py @@ -144,5 +144,6 @@ async def api_notifications(): for e in events ] ) - except Exception: + except Exception as exc: + logger.debug("System events fetch error: %s", exc) return JSONResponse([]) diff --git a/src/dashboard/routes/voice.py b/src/dashboard/routes/voice.py index 08dcc6f..00e7659 100644 --- a/src/dashboard/routes/voice.py +++ b/src/dashboard/routes/voice.py @@ -43,7 +43,8 @@ async def tts_status(): "available": voice_tts.available, "voices": voice_tts.get_voices() if voice_tts.available else [], } - except Exception: + except Exception as exc: + logger.debug("Voice config error: %s", exc) return {"available": False, "voices": []} @@ -139,7 +140,8 @@ async def process_voice_input( if voice_tts.available: voice_tts.speak(response_text) - except Exception: + except Exception as exc: + logger.debug("Voice TTS error: %s", exc) pass return { diff --git a/src/infrastructure/error_capture.py b/src/infrastructure/error_capture.py index 9053bcb..e6b18bb 100644 --- a/src/infrastructure/error_capture.py +++ b/src/infrastructure/error_capture.py @@ -87,7 +87,8 @@ def _get_git_context() -> dict: ).stdout.strip() return {"branch": branch, "commit": commit} - except Exception: + except Exception as exc: + logger.warning("Git info capture error: %s", exc) return {"branch": "unknown", "commit": "unknown"} @@ -199,7 +200,8 @@ def capture_error( "title": title[:100], }, ) - except Exception: + except Exception as exc: + logger.warning("Bug report screenshot error: %s", exc) pass except Exception as task_exc: @@ -214,7 +216,8 @@ def capture_error( message=f"{type(exc).__name__} in {source}: {str(exc)[:80]}", category="system", ) - except Exception: + except Exception as exc: + logger.warning("Bug report notification error: %s", exc) pass # 4. Record in session logger @@ -226,7 +229,8 @@ def capture_error( error=f"{type(exc).__name__}: {str(exc)}", context=source, ) - except Exception: + except Exception as exc: + logger.warning("Bug report session logging error: %s", exc) pass return task_id diff --git a/src/infrastructure/router/cascade.py b/src/infrastructure/router/cascade.py index e3aaea3..3b5e23a 100644 --- a/src/infrastructure/router/cascade.py +++ b/src/infrastructure/router/cascade.py @@ -304,7 +304,8 @@ class CascadeRouter: url = provider.url or "http://localhost:11434" response = requests.get(f"{url}/api/tags", timeout=5) return response.status_code == 200 - except Exception: + except Exception as exc: + logger.debug("Ollama provider check error: %s", exc) return False elif provider.type == "airllm": diff --git a/src/infrastructure/ws_manager/handler.py b/src/infrastructure/ws_manager/handler.py index 9beb0bf..978a195 100644 --- a/src/infrastructure/ws_manager/handler.py +++ b/src/infrastructure/ws_manager/handler.py @@ -54,7 +54,8 @@ class WebSocketManager: for event in list(self._event_history)[-20:]: try: await websocket.send_text(event.to_json()) - except Exception: + except Exception as exc: + logger.warning("WebSocket history send error: %s", exc) break def disconnect(self, websocket: WebSocket) -> None: @@ -83,8 +84,8 @@ class WebSocketManager: await ws.send_text(message) except ConnectionError: disconnected.append(ws) - except Exception: - logger.warning("Unexpected WebSocket send error", exc_info=True) + except Exception as exc: + logger.warning("Unexpected WebSocket send error: %s", exc) disconnected.append(ws) # Clean up dead connections @@ -156,7 +157,8 @@ class WebSocketManager: try: await ws.send_text(message) count += 1 - except Exception: + except Exception as exc: + logger.warning("WebSocket direct send error: %s", exc) disconnected.append(ws) # Clean up dead connections diff --git a/src/integrations/chat_bridge/vendors/discord.py b/src/integrations/chat_bridge/vendors/discord.py index 2defc69..6dfcea5 100644 --- a/src/integrations/chat_bridge/vendors/discord.py +++ b/src/integrations/chat_bridge/vendors/discord.py @@ -87,7 +87,8 @@ if _DISCORD_UI_AVAILABLE: await action["target"].send( f"Action `{action['tool_name']}` timed out and was auto-rejected." ) - except Exception: + except Exception as exc: + logger.warning("Discord action timeout message error: %s", exc) pass @@ -186,7 +187,8 @@ class DiscordVendor(ChatPlatform): if self._client and not self._client.is_closed(): try: await self._client.close() - except Exception: + except Exception as exc: + logger.warning("Discord client close error: %s", exc) pass self._client = None @@ -330,7 +332,8 @@ class DiscordVendor(ChatPlatform): if settings.discord_token: return settings.discord_token - except Exception: + except Exception as exc: + logger.warning("Discord token load error: %s", exc) pass # 2. Fall back to state file (set via /discord/setup endpoint) @@ -458,7 +461,8 @@ class DiscordVendor(ChatPlatform): req.reject(note="User rejected from Discord") try: await continue_chat(action["run_output"], action.get("session_id")) - except Exception: + except Exception as exc: + logger.warning("Discord continue chat error: %s", exc) pass await interaction.response.send_message( diff --git a/src/integrations/telegram_bot/bot.py b/src/integrations/telegram_bot/bot.py index c427a3e..d8c6dbe 100644 --- a/src/integrations/telegram_bot/bot.py +++ b/src/integrations/telegram_bot/bot.py @@ -56,7 +56,8 @@ class TelegramBot: from config import settings return settings.telegram_token or None - except Exception: + except Exception as exc: + logger.warning("Telegram token load error: %s", exc) return None def save_token(self, token: str) -> None: diff --git a/src/spark/engine.py b/src/spark/engine.py index 48f8264..89d59d1 100644 --- a/src/spark/engine.py +++ b/src/spark/engine.py @@ -358,7 +358,8 @@ def get_spark_engine() -> SparkEngine: from config import settings _spark_engine = SparkEngine(enabled=settings.spark_enabled) - except Exception: + except Exception as exc: + logger.debug("Spark engine settings load error: %s", exc) _spark_engine = SparkEngine(enabled=True) return _spark_engine diff --git a/src/spark/memory.py b/src/spark/memory.py index a604d11..973f816 100644 --- a/src/spark/memory.py +++ b/src/spark/memory.py @@ -10,12 +10,15 @@ spark_events — raw event log (every swarm event) spark_memories — consolidated insights extracted from event patterns """ +import logging import sqlite3 import uuid from dataclasses import dataclass from datetime import UTC, datetime from pathlib import Path +logger = logging.getLogger(__name__) + DB_PATH = Path("data/spark.db") # Importance thresholds @@ -170,7 +173,8 @@ def record_event( task_id=task_id or "", agent_id=agent_id or "", ) - except Exception: + except Exception as exc: + logger.debug("Spark event log error: %s", exc) pass # Graceful — don't break spark if event_log is unavailable return event_id diff --git a/src/timmy/agent.py b/src/timmy/agent.py index 911c3bd..36063bc 100644 --- a/src/timmy/agent.py +++ b/src/timmy/agent.py @@ -358,7 +358,8 @@ class TimmyWithMemory: if name: self.memory.update_user_fact("Name", name) self.memory.record_decision(f"Learned user's name: {name}") - except Exception: + except Exception as exc: + logger.warning("User name extraction failed: %s", exc) pass # Best-effort extraction def end_session(self, summary: str = "Session completed") -> None: diff --git a/src/timmy/agentic_loop.py b/src/timmy/agentic_loop.py index bff1c6a..df27c5d 100644 --- a/src/timmy/agentic_loop.py +++ b/src/timmy/agentic_loop.py @@ -332,5 +332,6 @@ async def _broadcast_progress(event: str, data: dict) -> None: from infrastructure.ws_manager.handler import ws_manager await ws_manager.broadcast(event, data) - except Exception: + except Exception as exc: + logger.warning("Agentic loop broadcast failed: %s", exc) logger.debug("Agentic loop: WS broadcast failed for %s", event) diff --git a/src/timmy/backends.py b/src/timmy/backends.py index 7c8f619..cf1ba8b 100644 --- a/src/timmy/backends.py +++ b/src/timmy/backends.py @@ -414,7 +414,8 @@ def grok_available() -> bool: from config import settings return settings.grok_enabled and bool(settings.xai_api_key) - except Exception: + except Exception as exc: + logger.warning("Backend check failed (grok_available): %s", exc) return False @@ -566,5 +567,6 @@ def claude_available() -> bool: from config import settings return bool(settings.anthropic_api_key) - except Exception: + except Exception as exc: + logger.warning("Backend check failed (claude_available): %s", exc) return False diff --git a/src/timmy/cli.py b/src/timmy/cli.py index 2d86c3e..b8f8598 100644 --- a/src/timmy/cli.py +++ b/src/timmy/cli.py @@ -259,7 +259,8 @@ def interview( from timmy.mcp_tools import close_mcp_sessions loop.run_until_complete(close_mcp_sessions()) - except Exception: + except Exception as exc: + logger.warning("MCP session close failed: %s", exc) pass loop.close() diff --git a/src/timmy/loop_qa.py b/src/timmy/loop_qa.py index 0b58cc2..a667333 100644 --- a/src/timmy/loop_qa.py +++ b/src/timmy/loop_qa.py @@ -262,7 +262,8 @@ def capture_error(exc, **kwargs): from infrastructure.error_capture import capture_error as _capture return _capture(exc, **kwargs) - except Exception: + except Exception as capture_exc: + logger.debug("Failed to capture error: %s", capture_exc) logger.debug("Failed to capture error", exc_info=True) diff --git a/src/timmy/memory/vector_store.py b/src/timmy/memory/vector_store.py index 925a249..37f951c 100644 --- a/src/timmy/memory/vector_store.py +++ b/src/timmy/memory/vector_store.py @@ -5,11 +5,14 @@ to retrieve relevant context from conversation history. """ import json +import logging import sqlite3 import uuid from dataclasses import dataclass, field from datetime import UTC, datetime +logger = logging.getLogger(__name__) + def _check_embedding_model() -> bool | None: """Check if the canonical embedding model is available.""" @@ -18,7 +21,8 @@ def _check_embedding_model() -> bool | None: model = _get_embedding_model() return model is not None and model is not False - except Exception: + except Exception as exc: + logger.debug("Embedding model check failed: %s", exc) return None diff --git a/src/timmy/thinking.py b/src/timmy/thinking.py index 591c178..d934803 100644 --- a/src/timmy/thinking.py +++ b/src/timmy/thinking.py @@ -177,7 +177,8 @@ class ThinkingEngine: latest = self.get_recent_thoughts(limit=1) if latest: self._last_thought_id = latest[0].id - except Exception: + except Exception as exc: + logger.debug("Failed to load recent thought: %s", exc) pass # Fresh start if DB doesn't exist yet async def think_once(self, prompt: str | None = None) -> Thought | None: @@ -578,7 +579,8 @@ class ThinkingEngine: ).fetchone()["c"] conn.close() parts.append(f"Thoughts today: {count}") - except Exception: + except Exception as exc: + logger.debug("Thought count query failed: %s", exc) pass # Recent chat activity (in-memory, no I/O) @@ -592,7 +594,8 @@ class ThinkingEngine: parts.append(f'Last chat ({last.role}): "{last.content[:80]}"') else: parts.append("No chat messages this session") - except Exception: + except Exception as exc: + logger.debug("Chat activity query failed: %s", exc) pass # Task queue (lightweight DB query) @@ -609,7 +612,8 @@ class ThinkingEngine: f"Tasks: {running} running, {pending} pending, " f"{done} completed, {failed} failed" ) - except Exception: + except Exception as exc: + logger.debug("Task queue query failed: %s", exc) pass return "\n".join(parts) if parts else "" diff --git a/src/timmy/tools.py b/src/timmy/tools.py index 08a8d24..e9d53ca 100644 --- a/src/timmy/tools.py +++ b/src/timmy/tools.py @@ -440,7 +440,8 @@ def consult_grok(query: str) -> str: tool_name="consult_grok", success=True, ) - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (consult_grok logging): %s", exc) pass # Generate Lightning invoice for monetization (unless free mode) @@ -453,7 +454,8 @@ def consult_grok(query: str) -> str: sats = min(settings.grok_max_sats_per_query, 100) inv = ln.create_invoice(sats, f"Grok query: {query[:50]}") invoice_info = f"\n[Lightning invoice: {sats} sats — {inv.payment_request[:40]}...]" - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (Lightning invoice): %s", exc) pass result = backend.run(query) @@ -512,7 +514,8 @@ def create_full_toolkit(base_dir: str | Path | None = None): if grok_available(): toolkit.register(consult_grok, name="consult_grok") logger.info("Grok consultation tool registered") - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (Grok registration): %s", exc) logger.debug("Grok tool not available") # Memory search, write, and forget — persistent recall across all channels @@ -523,7 +526,8 @@ def create_full_toolkit(base_dir: str | Path | None = None): toolkit.register(memory_write, name="memory_write") toolkit.register(memory_read, name="memory_read") toolkit.register(memory_forget, name="memory_forget") - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (Memory tools registration): %s", exc) logger.debug("Memory tools not available") # Agentic loop — background multi-step task execution @@ -569,7 +573,8 @@ def create_full_toolkit(base_dir: str | Path | None = None): ) toolkit.register(plan_and_execute, name="plan_and_execute") - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (plan_and_execute registration): %s", exc) logger.debug("plan_and_execute tool not available") # System introspection - query runtime environment (sovereign self-knowledge) @@ -579,7 +584,8 @@ def create_full_toolkit(base_dir: str | Path | None = None): toolkit.register(get_system_info, name="get_system_info") toolkit.register(check_ollama_health, name="check_ollama_health") toolkit.register(get_memory_status, name="get_memory_status") - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (Introspection tools registration): %s", exc) logger.debug("Introspection tools not available") # Inter-agent delegation - dispatch tasks to swarm agents @@ -588,7 +594,8 @@ def create_full_toolkit(base_dir: str | Path | None = None): toolkit.register(delegate_task, name="delegate_task") toolkit.register(list_swarm_agents, name="list_swarm_agents") - except Exception: + except Exception as exc: + logger.warning("Tool execution failed (Delegation tools registration): %s", exc) logger.debug("Delegation tools not available") # Gitea issue management is now provided by the gitea-mcp server diff --git a/src/timmy/tools_intro/__init__.py b/src/timmy/tools_intro/__init__.py index c2fb742..9f75bec 100644 --- a/src/timmy/tools_intro/__init__.py +++ b/src/timmy/tools_intro/__init__.py @@ -89,7 +89,8 @@ def _get_ollama_model() -> str: name = model.get("name", "") if name == configured or name == f"{configured}:latest": return configured - except Exception: + except Exception as exc: + logger.debug("Model validation failed: %s", exc) pass # Fallback to configured model @@ -186,7 +187,8 @@ def get_memory_status() -> dict[str, Any]: tier3_info["available"] = True tier3_info["vector_count"] = count[0] if count else 0 conn.close() - except Exception: + except Exception as exc: + logger.debug("Memory status query failed: %s", exc) pass # Self-coding journal stats @@ -212,7 +214,8 @@ def get_memory_status() -> dict[str, Any]: "success_rate": round(counts.get("success", 0) / total, 2) if total else 0, } conn.close() - except Exception: + except Exception as exc: + logger.debug("Journal stats query failed: %s", exc) pass return { @@ -303,7 +306,8 @@ def get_live_system_status() -> dict[str, Any]: uptime = (datetime.now(UTC) - _START_TIME).total_seconds() result["uptime_seconds"] = int(uptime) - except Exception: + except Exception as exc: + logger.debug("Uptime calculation failed: %s", exc) result["uptime_seconds"] = None # Discord status @@ -311,7 +315,8 @@ def get_live_system_status() -> dict[str, Any]: from integrations.chat_bridge.vendors.discord import discord_bot result["discord"] = {"state": discord_bot.state.name} - except Exception: + except Exception as exc: + logger.debug("Discord status check failed: %s", exc) result["discord"] = {"state": "unknown"} result["timestamp"] = datetime.now(UTC).isoformat() diff --git a/src/timmy/voice_loop.py b/src/timmy/voice_loop.py index d802402..8375fca 100644 --- a/src/timmy/voice_loop.py +++ b/src/timmy/voice_loop.py @@ -465,14 +465,16 @@ class VoiceLoop: try: self._loop.run_until_complete(self._loop.shutdown_asyncgens()) - except Exception: + except Exception as exc: + logger.debug("Shutdown asyncgens failed: %s", exc) pass with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) try: self._loop.close() - except Exception: + except Exception as exc: + logger.debug("Loop close failed: %s", exc) pass self._loop = None diff --git a/src/timmy_serve/voice_tts.py b/src/timmy_serve/voice_tts.py index 3ffbe2f..251b97f 100644 --- a/src/timmy_serve/voice_tts.py +++ b/src/timmy_serve/voice_tts.py @@ -87,7 +87,8 @@ class VoiceTTS: {"id": v.id, "name": v.name, "languages": getattr(v, "languages", [])} for v in voices ] - except Exception: + except Exception as exc: + logger.debug("Voice list retrieval failed: %s", exc) return [] def set_voice(self, voice_id: str) -> None: