diff --git a/autobot-backend/agents/base_agent.py b/autobot-backend/agents/base_agent.py index 6d9a9f0af..0c490551c 100644 --- a/autobot-backend/agents/base_agent.py +++ b/autobot-backend/agents/base_agent.py @@ -370,7 +370,10 @@ async def _handle_communication_request( return StandardMessage( header=MessageHeader(message_type=MessageType.ERROR), payload=MessagePayload( - content={"error": "Communication request failed", "error_type": type(e).__name__} + content={ + "error": "Communication request failed", + "error_type": type(e).__name__, + } ), ) diff --git a/autobot-backend/agents/knowledge_retrieval_agent.py b/autobot-backend/agents/knowledge_retrieval_agent.py index b60e5dce6..9402644d5 100644 --- a/autobot-backend/agents/knowledge_retrieval_agent.py +++ b/autobot-backend/agents/knowledge_retrieval_agent.py @@ -236,7 +236,11 @@ async def find_similar_documents( except Exception as e: logger.error("Similar document search error: %s", e) - return {"status": "error", "documents": [], "error": "Document search failed"} + return { + "status": "error", + "documents": [], + "error": "Document search failed", + } async def quick_fact_lookup( self, fact_query: str, max_docs: int = 3 diff --git a/autobot-backend/agents/librarian_assistant.py b/autobot-backend/agents/librarian_assistant.py index 30186aabb..cdd9ef78f 100644 --- a/autobot-backend/agents/librarian_assistant.py +++ b/autobot-backend/agents/librarian_assistant.py @@ -353,7 +353,9 @@ async def assess_content_quality( return self._parse_assessment_response(response, content_data) except Exception as e: logger.error("Error assessing content quality: %s", e) - return self._build_fallback_assessment(content_data, "Content quality assessment failed") + return self._build_fallback_assessment( + content_data, "Content quality assessment failed" + ) async def store_in_knowledge_base( self, content_data: Dict[str, Any], assessment: Dict[str, Any] diff --git a/autobot-backend/agents/npu_code_search_agent.py b/autobot-backend/agents/npu_code_search_agent.py index 8bc5d496c..34d1c30f6 100644 --- a/autobot-backend/agents/npu_code_search_agent.py +++ b/autobot-backend/agents/npu_code_search_agent.py @@ -411,7 +411,11 @@ async def index_codebase( except Exception as e: self.logger.error("Codebase indexing failed: %s", e) - return {"status": "error", "error": "Codebase indexing failed", "indexed_files": indexed_files} + return { + "status": "error", + "error": "Codebase indexing failed", + "indexed_files": indexed_files, + } def _build_file_index_data( self, relative_path: str, language: str, content: str, elements: Dict[str, List] diff --git a/autobot-backend/agents/system_knowledge_manager.py b/autobot-backend/agents/system_knowledge_manager.py index 53dc1955f..53b24b3a8 100644 --- a/autobot-backend/agents/system_knowledge_manager.py +++ b/autobot-backend/agents/system_knowledge_manager.py @@ -874,4 +874,8 @@ def get_knowledge_categories(self) -> Dict[str, Any]: except Exception as e: logger.error("Failed to get knowledge categories: %s", e) - return {"success": False, "error": "Failed to retrieve knowledge categories", "categories": {}} + return { + "success": False, + "error": "Failed to retrieve knowledge categories", + "categories": {}, + } diff --git a/autobot-backend/api/agent_config.py b/autobot-backend/api/agent_config.py index ab338168a..298aee57b 100644 --- a/autobot-backend/api/agent_config.py +++ b/autobot-backend/api/agent_config.py @@ -114,7 +114,9 @@ async def _get_available_providers() -> list: try: from services.provider_health import ProviderHealthManager - results = await ProviderHealthManager.check_all_providers(timeout=3.0, use_cache=True) + results = await ProviderHealthManager.check_all_providers( + timeout=3.0, use_cache=True + ) return [name for name, result in results.items() if result.available] except Exception as e: logger.warning("Could not check provider availability: %s", e) diff --git a/autobot-backend/api/analytics_controller.py b/autobot-backend/api/analytics_controller.py index b21908a2b..14bee32d6 100644 --- a/autobot-backend/api/analytics_controller.py +++ b/autobot-backend/api/analytics_controller.py @@ -64,7 +64,9 @@ re.compile(r"^\d+$"), # Alphanumeric slugs that look generated: starts with alpha/digit, contains # both letters and digits, length ≥ 8. Avoids collapsing short word slugs. - re.compile(r"^(?=[a-z0-9_-]{0,200}[a-z])(?=[a-z0-9_-]{0,200}\d)[a-z0-9_-]{8,}$", re.I), + re.compile( + r"^(?=[a-z0-9_-]{0,200}[a-z])(?=[a-z0-9_-]{0,200}\d)[a-z0-9_-]{8,}$", re.I + ), ] diff --git a/autobot-backend/api/codebase_analytics/endpoints/sources.py b/autobot-backend/api/codebase_analytics/endpoints/sources.py index 18d2602a7..05eb59772 100644 --- a/autobot-backend/api/codebase_analytics/endpoints/sources.py +++ b/autobot-backend/api/codebase_analytics/endpoints/sources.py @@ -94,7 +94,9 @@ async def _run_git_clone(url: str, dest: str, branch: str) -> str: stderr=asyncio.subprocess.PIPE, ) try: - _, stderr = await asyncio.wait_for(proc.communicate(), timeout=_GIT_TIMEOUT_SECONDS) + _, stderr = await asyncio.wait_for( + proc.communicate(), timeout=_GIT_TIMEOUT_SECONDS + ) except asyncio.TimeoutError: proc.kill() await proc.wait() @@ -119,7 +121,9 @@ async def _run_git_pull(clone_path: str) -> str: stderr=asyncio.subprocess.PIPE, ) try: - _, stderr = await asyncio.wait_for(proc.communicate(), timeout=_GIT_TIMEOUT_SECONDS) + _, stderr = await asyncio.wait_for( + proc.communicate(), timeout=_GIT_TIMEOUT_SECONDS + ) except asyncio.TimeoutError: proc.kill() await proc.wait() diff --git a/autobot-backend/api/intelligent_agent.py b/autobot-backend/api/intelligent_agent.py index aeadff280..ab228048a 100644 --- a/autobot-backend/api/intelligent_agent.py +++ b/autobot-backend/api/intelligent_agent.py @@ -360,8 +360,6 @@ async def websocket_stream(websocket: WebSocket): except Exception as e: logger.error("WebSocket error: %s", e) try: - await websocket.send_json( - {"type": "error", "content": "WebSocket error"} - ) + await websocket.send_json({"type": "error", "content": "WebSocket error"}) except Exception as conn_error: logger.debug("Connection error: %s", conn_error) # Connection closed diff --git a/autobot-backend/api/long_running_operations.py b/autobot-backend/api/long_running_operations.py index 2490f83b7..d0282c37c 100644 --- a/autobot-backend/api/long_running_operations.py +++ b/autobot-backend/api/long_running_operations.py @@ -184,9 +184,13 @@ async def start_codebase_indexing( from pathlib import Path try: - safe_codebase_path = Path(validate_path(request.codebase_path, must_exist=True)) + safe_codebase_path = Path( + validate_path(request.codebase_path, must_exist=True) + ) except (ValueError, PermissionError): - raise HTTPException(status_code=400, detail="Invalid or inaccessible codebase path") + raise HTTPException( + status_code=400, detail="Invalid or inaccessible codebase path" + ) estimated_files = 0 try: @@ -259,7 +263,9 @@ async def start_comprehensive_testing( try: safe_test_path = Path(validate_path(request.test_path, must_exist=True)) except (ValueError, PermissionError): - raise HTTPException(status_code=400, detail="Invalid or inaccessible test path") + raise HTTPException( + status_code=400, detail="Invalid or inaccessible test path" + ) estimated_tests = 0 try: diff --git a/autobot-backend/api/terminal_websocket.py b/autobot-backend/api/terminal_websocket.py index acc0e54bd..5b8a574a0 100644 --- a/autobot-backend/api/terminal_websocket.py +++ b/autobot-backend/api/terminal_websocket.py @@ -124,9 +124,7 @@ async def handle_terminal_session(self, websocket: WebSocket, chat_id: str): await self._send_error(websocket, "Invalid JSON") except Exception as e: logger.error(f"Error handling WebSocket message: {e}") - await self._send_error( - websocket, "Error processing message" - ) + await self._send_error(websocket, "Error processing message") except Exception as e: logger.error(f"WebSocket session error: {e}") diff --git a/autobot-backend/chat_workflow/graph_inject_warning_test.py b/autobot-backend/chat_workflow/graph_inject_warning_test.py index 5578ef6f2..10d3d11a1 100644 --- a/autobot-backend/chat_workflow/graph_inject_warning_test.py +++ b/autobot-backend/chat_workflow/graph_inject_warning_test.py @@ -75,7 +75,9 @@ class _SystemMessage(_BaseMessage): "langgraph": types.ModuleType("langgraph"), "langgraph.checkpoint": types.ModuleType("langgraph.checkpoint"), "langgraph.checkpoint.redis": types.ModuleType("langgraph.checkpoint.redis"), - "langgraph.checkpoint.redis.aio": types.ModuleType("langgraph.checkpoint.redis.aio"), + "langgraph.checkpoint.redis.aio": types.ModuleType( + "langgraph.checkpoint.redis.aio" + ), "langgraph.graph": types.ModuleType("langgraph.graph"), "langgraph.types": types.ModuleType("langgraph.types"), "typing_extensions": types.ModuleType("typing_extensions"), @@ -126,7 +128,9 @@ def test_appends_hint_to_prompt(self): result = _inject_mid_conversation_warning( "Avoid repeating tool calls.", "Answer the question." ) - assert result == "Answer the question.\n\n[Guidance: Avoid repeating tool calls.]" + assert ( + result == "Answer the question.\n\n[Guidance: Avoid repeating tool calls.]" + ) def test_empty_prompt(self): """Helper works when initial_prompt is empty.""" @@ -195,9 +199,13 @@ def test_mid_conversation_system_message_rejected(self): messages = [ SystemMessage(content="You are a helpful assistant."), HumanMessage(content="Hello"), - SystemMessage(content="[Warning: loop detected]"), # mid-conversation — WRONG + SystemMessage( + content="[Warning: loop detected]" + ), # mid-conversation — WRONG ] - with pytest.raises(ValueError, match="Anthropic does not support system messages"): + with pytest.raises( + ValueError, match="Anthropic does not support system messages" + ): self._mock_format_messages(messages) def test_human_message_injection_accepted(self): diff --git a/autobot-backend/chat_workflow/tool_handler.py b/autobot-backend/chat_workflow/tool_handler.py index 260d041d3..59cd1f640 100644 --- a/autobot-backend/chat_workflow/tool_handler.py +++ b/autobot-backend/chat_workflow/tool_handler.py @@ -1318,7 +1318,11 @@ async def _handle_browser_tool( except Exception as e: logger.error("[Issue #1368] Browser tool '%s' failed: %s", tool_name, e) execution_results.append( - {"tool": tool_name, "status": "error", "error": "Browser tool execution failed"} + { + "tool": tool_name, + "status": "error", + "error": "Browser tool execution failed", + } ) yield WorkflowMessage( type="error", diff --git a/autobot-backend/code_analysis/auto-tools/logging_standardizer.py b/autobot-backend/code_analysis/auto-tools/logging_standardizer.py index 9cbd92d0e..67d67cd27 100644 --- a/autobot-backend/code_analysis/auto-tools/logging_standardizer.py +++ b/autobot-backend/code_analysis/auto-tools/logging_standardizer.py @@ -438,7 +438,10 @@ def process_file(self, file_path: Path) -> bool: except Exception as e: self.report["errors"].append( - {"file": str(file_path.relative_to(self.project_root)), "error": "File standardization failed"} + { + "file": str(file_path.relative_to(self.project_root)), + "error": "File standardization failed", + } ) return False diff --git a/autobot-backend/code_analysis/auto-tools/performance_optimizer.py b/autobot-backend/code_analysis/auto-tools/performance_optimizer.py index 93949ef8d..61cd159cd 100644 --- a/autobot-backend/code_analysis/auto-tools/performance_optimizer.py +++ b/autobot-backend/code_analysis/auto-tools/performance_optimizer.py @@ -339,7 +339,10 @@ def process_file(self, file_path: Path) -> bool: except Exception as e: self.report["errors"].append( - {"file": str(file_path.relative_to(self.project_root)), "error": "File optimization failed"} + { + "file": str(file_path.relative_to(self.project_root)), + "error": "File optimization failed", + } ) return False diff --git a/autobot-backend/code_analysis/auto-tools/playwright_sanitizer.py b/autobot-backend/code_analysis/auto-tools/playwright_sanitizer.py index ca16a56a4..95baa38f3 100644 --- a/autobot-backend/code_analysis/auto-tools/playwright_sanitizer.py +++ b/autobot-backend/code_analysis/auto-tools/playwright_sanitizer.py @@ -373,7 +373,11 @@ def fix_playwright_report(self, file_path: str) -> Dict[str, Any]: except Exception as e: logger.error("Error processing %s: %s", file_path, e) - return {"file": file_path, "status": "error", "error": "File processing failed"} + return { + "file": file_path, + "status": "error", + "error": "File processing failed", + } def _compute_report_stats(self, results: List[Dict[str, Any]]) -> Dict[str, int]: """ diff --git a/autobot-backend/code_analysis/auto-tools/security_deep_sanitizer.py b/autobot-backend/code_analysis/auto-tools/security_deep_sanitizer.py index 4ef890f49..6c6b64951 100644 --- a/autobot-backend/code_analysis/auto-tools/security_deep_sanitizer.py +++ b/autobot-backend/code_analysis/auto-tools/security_deep_sanitizer.py @@ -589,7 +589,11 @@ def fix_file(self, file_path: str) -> Dict[str, Any]: except Exception as e: logger.error("Error processing file %sfile_path : %se ") - return {"file": file_path, "status": "error", "error": "File processing failed"} + return { + "file": file_path, + "status": "error", + "error": "File processing failed", + } def scan_directory(self, directory: str) -> List[str]: """Scan directory for HTML files to fix.""" diff --git a/autobot-backend/code_analysis/auto-tools/security_sanitizer.py b/autobot-backend/code_analysis/auto-tools/security_sanitizer.py index ffe4f7bbb..7eadeba61 100644 --- a/autobot-backend/code_analysis/auto-tools/security_sanitizer.py +++ b/autobot-backend/code_analysis/auto-tools/security_sanitizer.py @@ -373,7 +373,11 @@ def fix_file(self, file_path: str) -> Dict[str, Any]: except Exception as e: logger.error("Error processing file %sfile_path : %se ") - return {"file": file_path, "status": "error", "error": "File processing failed"} + return { + "file": file_path, + "status": "error", + "error": "File processing failed", + } def scan_directory(self, directory: str) -> List[str]: """Scan directory for HTML files to fix.""" diff --git a/autobot-backend/code_intelligence/pattern_analysis/analyzer.py b/autobot-backend/code_intelligence/pattern_analysis/analyzer.py index 71e5dead4..d6c4f2dcb 100644 --- a/autobot-backend/code_intelligence/pattern_analysis/analyzer.py +++ b/autobot-backend/code_intelligence/pattern_analysis/analyzer.py @@ -594,7 +594,11 @@ async def _run_clone_detection(self, directory: str) -> Dict[str, Any]: except Exception as e: logger.error("Clone detection failed: %s", e) - return {"type": "clone_detection", "patterns": [], "error": "Clone detection failed"} + return { + "type": "clone_detection", + "patterns": [], + "error": "Clone detection failed", + } async def _run_regex_detection(self, directory: str) -> Dict[str, Any]: """Run regex optimization detection. @@ -620,7 +624,11 @@ async def _run_regex_detection(self, directory: str) -> Dict[str, Any]: except Exception as e: logger.error("Regex detection failed: %s", e) - return {"type": "regex_detection", "patterns": [], "error": "Regex detection failed"} + return { + "type": "regex_detection", + "patterns": [], + "error": "Regex detection failed", + } async def _run_complexity_analysis(self, directory: str) -> Dict[str, Any]: """Run complexity analysis. diff --git a/autobot-backend/conversation.py b/autobot-backend/conversation.py index 94be10bf5..bd9869872 100644 --- a/autobot-backend/conversation.py +++ b/autobot-backend/conversation.py @@ -744,7 +744,9 @@ async def _conduct_research(self, user_message: str) -> Dict[str, Any]: except Exception as e: logger.error("Research failed: %s", e) - self._add_system_message("External research failed", "debug", {"error": True}) + self._add_system_message( + "External research failed", "debug", {"error": True} + ) return {"success": False, "error": "External research failed"} def _generate_search_queries(self, user_message: str) -> List[str]: diff --git a/autobot-backend/dependency_container.py b/autobot-backend/dependency_container.py index 1797ef0e2..14fa6b94c 100644 --- a/autobot-backend/dependency_container.py +++ b/autobot-backend/dependency_container.py @@ -339,7 +339,10 @@ async def health_check_all_services(self) -> Dict[str, Dict[str, Any]]: } except Exception as e: logger.error("Health check failed for service %s: %s", service_name, e) - results[service_name] = {"status": "unhealthy", "error": "Health check failed"} + results[service_name] = { + "status": "unhealthy", + "error": "Health check failed", + } return results diff --git a/autobot-backend/diagnostics.py b/autobot-backend/diagnostics.py index bbf02e439..9d815f77c 100644 --- a/autobot-backend/diagnostics.py +++ b/autobot-backend/diagnostics.py @@ -96,7 +96,10 @@ def _get_system_info(self) -> Dict[str, Any]: } except Exception as e: logger.error("Error gathering system info: %s", e) - return {"error": "Failed to gather system info", "timestamp": datetime.now().isoformat()} + return { + "error": "Failed to gather system info", + "timestamp": datetime.now().isoformat(), + } def _get_gpu_info(self) -> Dict[str, Any]: """Get GPU information for performance monitoring""" @@ -450,7 +453,12 @@ def _generate_performance_recommendations(self) -> List[Dict[str, str]]: except Exception as e: logger.error("Error generating recommendations: %s", e) - return [{"category": "error", "recommendation": "Error generating recommendations"}] + return [ + { + "category": "error", + "recommendation": "Error generating recommendations", + } + ] def cleanup_and_optimize_memory(self): """Force memory cleanup and optimization""" diff --git a/autobot-backend/elevation_wrapper.py b/autobot-backend/elevation_wrapper.py index 8694edcb4..a87781a5b 100644 --- a/autobot-backend/elevation_wrapper.py +++ b/autobot-backend/elevation_wrapper.py @@ -166,7 +166,11 @@ async def _execute_normal(self, command: str) -> Dict: except Exception as e: logger.error("Normal execution failed: %s", e) - return {"success": False, "error": "Command execution failed", "return_code": -1} + return { + "success": False, + "error": "Command execution failed", + "return_code": -1, + } async def _execute_elevated(self, command: str, session_token: str) -> Dict: """Execute command with elevation using session token""" @@ -186,7 +190,11 @@ async def _execute_elevated(self, command: str, session_token: str) -> Dict: except Exception as e: logger.error("Elevated execution failed: %s", e) - return {"success": False, "error": "Elevated command execution failed", "return_code": -1} + return { + "success": False, + "error": "Elevated command execution failed", + "return_code": -1, + } def clear_session(self): """Clear the current elevation session""" diff --git a/autobot-backend/initialization/lifespan.py b/autobot-backend/initialization/lifespan.py index 858feaa6f..03232993f 100644 --- a/autobot-backend/initialization/lifespan.py +++ b/autobot-backend/initialization/lifespan.py @@ -645,13 +645,14 @@ async def _launch_workflow(workflow_id: str, payload: dict) -> None: """Launcher callback invoked by TriggerService when a trigger fires.""" from services.workflow_automation import get_workflow_manager - logger.info("Trigger fired for workflow %s with payload keys=%s", - workflow_id, list(payload.keys()) if payload else []) + logger.info( + "Trigger fired for workflow %s with payload keys=%s", + workflow_id, + list(payload.keys()) if payload else [], + ) mgr = get_workflow_manager() if mgr: - await mgr.start_workflow_execution( - workflow_id, trigger_payload=payload - ) + await mgr.start_workflow_execution(workflow_id, trigger_payload=payload) await trigger_service.start(launcher=_launch_workflow) app.state.trigger_service = trigger_service diff --git a/autobot-backend/judges/__init__.py b/autobot-backend/judges/__init__.py index ccc5fb7b0..8d9a3c89f 100644 --- a/autobot-backend/judges/__init__.py +++ b/autobot-backend/judges/__init__.py @@ -129,7 +129,9 @@ async def make_judgment( except Exception as e: logger.error("Error in %s judgment: %s", self.judge_type, e) - return await self._create_error_judgment(subject, "Judgment evaluation failed") + return await self._create_error_judgment( + subject, "Judgment evaluation failed" + ) async def _finalize_judgment_result( self, judgment_result: JudgmentResult, start_time: datetime diff --git a/autobot-backend/knowledge/facts.py b/autobot-backend/knowledge/facts.py index f982ab3f3..f57d52d95 100644 --- a/autobot-backend/knowledge/facts.py +++ b/autobot-backend/knowledge/facts.py @@ -1300,7 +1300,9 @@ async def _delete_single_fact_for_session( except Exception as e: logger.error("Failed to delete fact %s: %s", fact_id, e) - result["errors"].append({"fact_id": fact_id, "error": "Fact deletion failed"}) + result["errors"].append( + {"fact_id": fact_id, "error": "Fact deletion failed"} + ) async def _process_session_facts_deletion( self, @@ -1376,7 +1378,9 @@ async def delete_facts_by_session( except Exception as e: logger.error("Failed to delete facts for session %s: %s", session_id, e) - result["errors"].append({"session_id": session_id, "error": "Session facts deletion failed"}) + result["errors"].append( + {"session_id": session_id, "error": "Session facts deletion failed"} + ) return result async def _cleanup_session_tracking( diff --git a/autobot-backend/knowledge/metadata.py b/autobot-backend/knowledge/metadata.py index 47d634471..4e951e584 100644 --- a/autobot-backend/knowledge/metadata.py +++ b/autobot-backend/knowledge/metadata.py @@ -242,7 +242,11 @@ async def list_metadata_templates(self, category: str = None) -> Dict[str, Any]: except Exception as e: logger.error("Failed to list metadata templates: %s", e) - return {"status": "error", "message": "Metadata operation failed", "templates": []} + return { + "status": "error", + "message": "Metadata operation failed", + "templates": [], + } async def _update_template_category_links( self, template_id: str, old_categories: set, new_categories: set @@ -393,7 +397,11 @@ async def validate_metadata( except Exception as e: logger.error("Failed to validate metadata: %s", e) - return {"valid": False, "errors": ["Metadata validation failed"], "warnings": []} + return { + "valid": False, + "errors": ["Metadata validation failed"], + "warnings": [], + } def _validate_field_type(self, field_name: str, value: Any, field_type: str) -> str: """Validate a field value against its expected type. Returns error or None.""" @@ -469,7 +477,11 @@ async def apply_template_defaults( except Exception as e: logger.error("Failed to apply template defaults: %s", e) - return {"status": "error", "message": "Metadata operation failed", "metadata": metadata} + return { + "status": "error", + "message": "Metadata operation failed", + "metadata": metadata, + } def _match_metadata_value( self, field_value: Any, value: Any, operator: str @@ -548,7 +560,11 @@ async def search_by_metadata( except Exception as e: logger.error("Failed to search by metadata: %s", e) - return {"status": "error", "message": "Metadata operation failed", "fact_ids": []} + return { + "status": "error", + "message": "Metadata operation failed", + "fact_ids": [], + } def ensure_initialized(self): """Ensure the knowledge base is initialized. Implemented in composed class.""" diff --git a/autobot-backend/knowledge/search.py b/autobot-backend/knowledge/search.py index 84d96dd15..6053e7296 100644 --- a/autobot-backend/knowledge/search.py +++ b/autobot-backend/knowledge/search.py @@ -462,7 +462,12 @@ async def enhanced_search( ) except Exception as e: logger.error("Enhanced search failed: %s", e) - return {"success": False, "results": [], "total_count": 0, "error": "Search failed"} + return { + "success": False, + "results": [], + "total_count": 0, + "error": "Search failed", + } def _preprocess_query(self, query: str) -> str: """Preprocess search query for better results. Issue #78: Query preprocessing.""" @@ -775,7 +780,12 @@ async def enhanced_search_v2_ctx( import traceback logger.error(traceback.format_exc()) - return {"success": False, "results": [], "total_count": 0, "error": "Search failed"} + return { + "success": False, + "results": [], + "total_count": 0, + "error": "Search failed", + } def _expand_query_terms(self, query: str, enable_expansion: bool) -> List[str]: """Expand query with synonyms and related terms.""" diff --git a/autobot-backend/knowledge/stats.py b/autobot-backend/knowledge/stats.py index 00a473354..01b607463 100644 --- a/autobot-backend/knowledge/stats.py +++ b/autobot-backend/knowledge/stats.py @@ -506,7 +506,11 @@ async def get_detailed_stats(self) -> Dict[str, Any]: except Exception as e: logger.error("Error generating detailed stats: %s", e) - return {**basic_stats, "detailed_stats": False, "error": "Failed to generate detailed stats"} + return { + **basic_stats, + "detailed_stats": False, + "error": "Failed to generate detailed stats", + } async def _calc_all_quality_dimensions( self, facts: List[Dict[str, Any]] diff --git a/autobot-backend/knowledge/suggestions.py b/autobot-backend/knowledge/suggestions.py index cb6da9142..6eec7de44 100644 --- a/autobot-backend/knowledge/suggestions.py +++ b/autobot-backend/knowledge/suggestions.py @@ -107,7 +107,11 @@ async def suggest_tags( except Exception as e: logger.error("Failed to suggest tags: %s", e) - return {"success": False, "suggestions": [], "error": "Failed to suggest tags"} + return { + "success": False, + "suggestions": [], + "error": "Failed to suggest tags", + } async def suggest_categories( self, @@ -146,7 +150,11 @@ async def suggest_categories( except Exception as e: logger.error("Failed to suggest categories: %s", e) - return {"success": False, "suggestions": [], "error": "Failed to suggest categories"} + return { + "success": False, + "suggestions": [], + "error": "Failed to suggest categories", + } def _empty_suggestion_response(self, error: str = None) -> Dict[str, Any]: """Build empty suggestion response (Issue #398: extracted).""" @@ -300,7 +308,11 @@ async def auto_apply_suggestions( except Exception as e: logger.error("Failed to auto-apply suggestions: %s", e) - return {"success": False, "fact_id": fact_id, "error": "Failed to apply suggestions"} + return { + "success": False, + "fact_id": fact_id, + "error": "Failed to apply suggestions", + } async def _find_similar_documents( self, content: str, limit: int diff --git a/autobot-backend/knowledge/versioning.py b/autobot-backend/knowledge/versioning.py index 64afd0062..40e0c47da 100644 --- a/autobot-backend/knowledge/versioning.py +++ b/autobot-backend/knowledge/versioning.py @@ -208,7 +208,11 @@ async def list_versions(self, fact_id: str, limit: int = 10) -> Dict[str, Any]: except Exception as e: logger.error("Failed to list versions for %s: %s", fact_id, e) - return {"status": "error", "message": "Versioning operation failed", "versions": []} + return { + "status": "error", + "message": "Versioning operation failed", + "versions": [], + } async def _apply_version_to_fact( self, fact_id: str, target_version: Dict[str, Any] diff --git a/autobot-backend/knowledge_factory.py b/autobot-backend/knowledge_factory.py index 0b3265cd5..6321371a5 100644 --- a/autobot-backend/knowledge_factory.py +++ b/autobot-backend/knowledge_factory.py @@ -144,7 +144,8 @@ async def get_or_create_knowledge_base(app: FastAPI, force_refresh: bool = False if elapsed < KB_RETRY_COOLDOWN_SECONDS: remaining = int(KB_RETRY_COOLDOWN_SECONDS - elapsed) logger.debug( - "KB init cooldown active — skipping retry (%ds remaining)", remaining + "KB init cooldown active — skipping retry (%ds remaining)", + remaining, ) return None diff --git a/autobot-backend/llm_interface_pkg/adapters/layer_inference_adapter.py b/autobot-backend/llm_interface_pkg/adapters/layer_inference_adapter.py index 5dce7f6bd..ec30fa1e8 100644 --- a/autobot-backend/llm_interface_pkg/adapters/layer_inference_adapter.py +++ b/autobot-backend/llm_interface_pkg/adapters/layer_inference_adapter.py @@ -102,7 +102,10 @@ async def execute( try: result = await asyncio.to_thread( - self._pipeline.execute, prompt, prepared, max_new_tokens=max_tokens, + self._pipeline.execute, + prompt, + prepared, + max_new_tokens=max_tokens, ) except Exception: logger.exception("LayerInference generation failed") diff --git a/autobot-backend/llm_interface_pkg/interface.py b/autobot-backend/llm_interface_pkg/interface.py index 1136baded..7fd81d265 100644 --- a/autobot-backend/llm_interface_pkg/interface.py +++ b/autobot-backend/llm_interface_pkg/interface.py @@ -1273,15 +1273,11 @@ async def _handle_local_request(self, request: LLMRequest) -> LLMResponse: """Handle local requests via handler.""" return await self._local_handler.chat_completion(request) - async def _handle_layer_inference_request( - self, request: LLMRequest - ) -> LLMResponse: + async def _handle_layer_inference_request(self, request: LLMRequest) -> LLMResponse: """Handle layer-by-layer inference requests via adapter (#3104).""" adapter = self._adapter_registry.get("layer_inference") if not adapter: - raise ValueError( - "LayerInferenceAdapter not registered in adapter registry" - ) + raise ValueError("LayerInferenceAdapter not registered in adapter registry") return await adapter.execute(request) # Utility methods diff --git a/autobot-backend/llm_interface_pkg/optimization/hf_quantizer.py b/autobot-backend/llm_interface_pkg/optimization/hf_quantizer.py index 185904d68..edd85450d 100644 --- a/autobot-backend/llm_interface_pkg/optimization/hf_quantizer.py +++ b/autobot-backend/llm_interface_pkg/optimization/hf_quantizer.py @@ -378,7 +378,9 @@ def _preprocess_bitsandbytes(self) -> Dict[str, Any]: if self._config.extra_kwargs.get("load_in_8bit"): bnb_kwargs = {"load_in_8bit": True} elif self._config.extra_kwargs.get("load_in_4bit") is not None: - bnb_kwargs = {"load_in_4bit": bool(self._config.extra_kwargs["load_in_4bit"])} + bnb_kwargs = { + "load_in_4bit": bool(self._config.extra_kwargs["load_in_4bit"]) + } bnb_config = transformers.BitsAndBytesConfig(**bnb_kwargs) return { "quantization_config": bnb_config, diff --git a/autobot-backend/llm_interface_pkg/optimization/model_inspector.py b/autobot-backend/llm_interface_pkg/optimization/model_inspector.py index 00789fb46..9b4c93f98 100644 --- a/autobot-backend/llm_interface_pkg/optimization/model_inspector.py +++ b/autobot-backend/llm_interface_pkg/optimization/model_inspector.py @@ -130,7 +130,9 @@ def _cache_put(model_name: str, info: ModelInfo) -> None: # --------------------------------------------------------------------------- -def _extract_from_config(cfg: Any, param_count_override: Optional[int] = None) -> ModelInfo: +def _extract_from_config( + cfg: Any, param_count_override: Optional[int] = None +) -> ModelInfo: """ Build a ModelInfo from a transformers PretrainedConfig object. @@ -154,9 +156,7 @@ def _extract_from_config(cfg: Any, param_count_override: Optional[int] = None) - or 0 ) num_attention_heads = ( - getattr(cfg, "num_attention_heads", None) - or getattr(cfg, "n_head", None) - or 0 + getattr(cfg, "num_attention_heads", None) or getattr(cfg, "n_head", None) or 0 ) vocab_size = getattr(cfg, "vocab_size", 0) or 0 @@ -193,7 +193,9 @@ def _estimate_param_count(num_layers: int, hidden_size: int, vocab_size: int) -> return embedding_params + num_layers * per_layer_params -def _count_params_via_skeleton(cfg: Any, transformers: Any, accelerate: Any) -> Optional[int]: +def _count_params_via_skeleton( + cfg: Any, transformers: Any, accelerate: Any +) -> Optional[int]: """ Instantiate an empty-weight model skeleton and return its exact param count. @@ -265,7 +267,9 @@ def _inspect_via_config(model_name: str) -> Optional[ModelInfo]: transformers = _import_transformers() accelerate = _import_accelerate() except ImportError as exc: - logger.warning("model_inspector: dependency missing for %s — %s", model_name, exc) + logger.warning( + "model_inspector: dependency missing for %s — %s", model_name, exc + ) return None try: diff --git a/autobot-backend/llm_interface_pkg/optimization/model_inspector_test.py b/autobot-backend/llm_interface_pkg/optimization/model_inspector_test.py index 19fe97c3b..1b36b93bc 100644 --- a/autobot-backend/llm_interface_pkg/optimization/model_inspector_test.py +++ b/autobot-backend/llm_interface_pkg/optimization/model_inspector_test.py @@ -27,7 +27,6 @@ inspect_model, ) - # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- @@ -174,9 +173,17 @@ def test_fallback_attributes_n_layer(self): def test_zero_config_returns_zero_params(self): """All-zero config produces zero param_count.""" cfg = MagicMock() - for attr in ("num_hidden_layers", "num_layers", "n_layer", - "hidden_size", "d_model", "n_embd", - "num_attention_heads", "n_head", "vocab_size"): + for attr in ( + "num_hidden_layers", + "num_layers", + "n_layer", + "hidden_size", + "d_model", + "n_embd", + "num_attention_heads", + "n_head", + "vocab_size", + ): setattr(cfg, attr, 0) info = _extract_from_config(cfg) assert info.param_count == 0 @@ -226,7 +233,9 @@ def test_returns_none_on_exception(self): """Returns None when from_config raises, without propagating the error.""" cfg = _make_config() transformers = MagicMock(name="transformers") - transformers.AutoModelForCausalLM.from_config.side_effect = RuntimeError("unsupported arch") + transformers.AutoModelForCausalLM.from_config.side_effect = RuntimeError( + "unsupported arch" + ) accelerate = _make_accelerate_mock() result = _count_params_via_skeleton(cfg, transformers, accelerate) @@ -328,8 +337,12 @@ def test_returns_none_when_accelerate_missing(self): def test_returns_model_info_with_skeleton_param_count(self): """inspect_model uses skeleton param count when available.""" - cfg = _make_config(num_hidden_layers=32, hidden_size=4096, - num_attention_heads=32, vocab_size=32000) + cfg = _make_config( + num_hidden_layers=32, + hidden_size=4096, + num_attention_heads=32, + vocab_size=32000, + ) mock_transformers = _make_transformers_mock(param_count=7_241_732_096) mock_transformers.AutoConfig = MagicMock() mock_transformers.AutoConfig.from_pretrained.return_value = cfg @@ -358,7 +371,9 @@ def test_falls_back_to_formula_when_skeleton_fails(self): mock_transformers = MagicMock(name="transformers") mock_transformers.AutoConfig = MagicMock() mock_transformers.AutoConfig.from_pretrained.return_value = cfg - mock_transformers.AutoModelForCausalLM.from_config.side_effect = RuntimeError("no arch") + mock_transformers.AutoModelForCausalLM.from_config.side_effect = RuntimeError( + "no arch" + ) mock_accelerate = _make_accelerate_mock() with ( @@ -405,7 +420,9 @@ def test_caches_result_on_success(self): def test_returns_none_on_config_fetch_failure(self): """inspect_model returns None when AutoConfig.from_pretrained raises.""" mock_transformers = MagicMock(name="transformers") - mock_transformers.AutoConfig.from_pretrained.side_effect = OSError("hub unavailable") + mock_transformers.AutoConfig.from_pretrained.side_effect = OSError( + "hub unavailable" + ) mock_accelerate = _make_accelerate_mock() with ( diff --git a/autobot-backend/llm_interface_pkg/optimization/pipeline.py b/autobot-backend/llm_interface_pkg/optimization/pipeline.py index f17001db9..11718cc24 100644 --- a/autobot-backend/llm_interface_pkg/optimization/pipeline.py +++ b/autobot-backend/llm_interface_pkg/optimization/pipeline.py @@ -25,7 +25,10 @@ from dataclasses import dataclass, field from typing import Any, Dict, Optional -from .attention_backend import AttentionBackendSelector, ModelConfig as AttentionModelConfig +from .attention_backend import ( + AttentionBackendSelector, + ModelConfig as AttentionModelConfig, +) from .hf_quantizer import HfQuantizerWrapper, QuantizerConfig, QuantizationType from .kv_cache import KVCacheConfig, KVCacheManager, LayerKVCache from .layer_inference import LayerInferenceConfig, LayerInferenceEngine @@ -224,7 +227,10 @@ def _log_prepare_result(self, prepared: PreparedPipeline, elapsed: float) -> Non kv_layers = prepared.kv_cache.config.num_layers if prepared.kv_cache else 0 logger.info( "Pipeline.prepare: done in %.3fs quant=%s attn=%s kv_layers=%d", - elapsed, quant_type, prepared.attention_backend, kv_layers, + elapsed, + quant_type, + prepared.attention_backend, + kv_layers, ) def _try_build_quantizer(self, model_cfg): diff --git a/autobot-backend/llm_multi_provider.py b/autobot-backend/llm_multi_provider.py index 1c84626a9..63eb1e4a0 100644 --- a/autobot-backend/llm_multi_provider.py +++ b/autobot-backend/llm_multi_provider.py @@ -781,7 +781,9 @@ async def health_check(self) -> Dict[str, Any]: health["overall_healthy"] = False except Exception as e: - logger.error("Health check failed for provider %s: %s", provider_type.value, e) + logger.error( + "Health check failed for provider %s: %s", provider_type.value, e + ) health["providers"][provider_type.value] = { "available": False, "enabled": provider.config.enabled, diff --git a/autobot-backend/llm_providers/custom_openai_provider.py b/autobot-backend/llm_providers/custom_openai_provider.py index eae5efc9f..3be75b88d 100644 --- a/autobot-backend/llm_providers/custom_openai_provider.py +++ b/autobot-backend/llm_providers/custom_openai_provider.py @@ -69,9 +69,7 @@ def __init__( def _resolve_base_url(self) -> str: """Resolve the endpoint base URL from settings or environment.""" - url = self._get_setting("base_url") or os.getenv( - "CUSTOM_OPENAI_BASE_URL", "" - ) + url = self._get_setting("base_url") or os.getenv("CUSTOM_OPENAI_BASE_URL", "") if not url: raise ValueError( "Custom OpenAI base_url not configured. " @@ -82,9 +80,7 @@ def _resolve_base_url(self) -> str: def _resolve_api_key(self) -> str: """Resolve the API key (many local servers accept any non-empty string).""" return ( - self._get_setting("api_key") - or os.getenv("CUSTOM_OPENAI_API_KEY") - or "none" + self._get_setting("api_key") or os.getenv("CUSTOM_OPENAI_API_KEY") or "none" ) def _ensure_client(self): diff --git a/autobot-backend/llm_providers/huggingface_provider.py b/autobot-backend/llm_providers/huggingface_provider.py index a0c9659e5..376d2e6f0 100644 --- a/autobot-backend/llm_providers/huggingface_provider.py +++ b/autobot-backend/llm_providers/huggingface_provider.py @@ -174,6 +174,7 @@ async def stream_completion(self, request: LLMRequest) -> AsyncIterator[str]: if chunk_json == "[DONE]": break import json + chunk = json.loads(chunk_json) delta = chunk["choices"][0].get("delta", {}).get("content") if delta: diff --git a/autobot-backend/llm_providers/ollama_provider.py b/autobot-backend/llm_providers/ollama_provider.py index dec444a2e..edca4a3f2 100644 --- a/autobot-backend/llm_providers/ollama_provider.py +++ b/autobot-backend/llm_providers/ollama_provider.py @@ -52,10 +52,7 @@ def _resolve_base_url(self) -> str: """Resolve the Ollama base URL from settings, SSOT config, or env.""" if self._base_url: return self._base_url - self._base_url = ( - self._get_setting("base_url") - or get_ollama_url() - ) + self._base_url = self._get_setting("base_url") or get_ollama_url() return self._base_url def _ensure_delegate(self): @@ -98,6 +95,7 @@ async def chat_completion(self, request: LLMRequest) -> LLMResponse: self._total_errors += 1 logger.error("OllamaProvider delegation error: %s", exc) import time + return LLMResponse( content="", model=request.model_name or "", diff --git a/autobot-backend/llm_providers/openai_provider.py b/autobot-backend/llm_providers/openai_provider.py index e7d51b276..67d6c80b3 100644 --- a/autobot-backend/llm_providers/openai_provider.py +++ b/autobot-backend/llm_providers/openai_provider.py @@ -65,6 +65,7 @@ def _resolve_api_key(self) -> Optional[str]: if not key: try: from config import ConfigManager + key = ConfigManager().get_api_key("openai") except Exception: pass diff --git a/autobot-backend/llm_providers/provider_registry.py b/autobot-backend/llm_providers/provider_registry.py index f60a5e22e..d850244da 100644 --- a/autobot-backend/llm_providers/provider_registry.py +++ b/autobot-backend/llm_providers/provider_registry.py @@ -96,7 +96,9 @@ def set_fallback_chain(self, chain: List[str]) -> None: # Per-conversation overrides # ------------------------------------------------------------------ - def set_conversation_provider(self, conversation_id: str, provider_name: str) -> None: + def set_conversation_provider( + self, conversation_id: str, provider_name: str + ) -> None: """Pin a specific provider for a given conversation.""" self._conversation_overrides[conversation_id] = provider_name logger.debug( @@ -265,8 +267,10 @@ def _populate_default_providers(registry: ProviderRegistry) -> None: # Ollama (local) — always registered, highest priority try: ssot = get_ssot_config() - ollama_url = ssot.ollama_url if ssot else os.getenv( - "AUTOBOT_OLLAMA_ENDPOINT", "http://127.0.0.1:11434" + ollama_url = ( + ssot.ollama_url + if ssot + else os.getenv("AUTOBOT_OLLAMA_ENDPOINT", "http://127.0.0.1:11434") ) from llm_providers.ollama_provider import OllamaProvider diff --git a/autobot-backend/npu_integration.py b/autobot-backend/npu_integration.py index 0929090d0..cbfb41373 100644 --- a/autobot-backend/npu_integration.py +++ b/autobot-backend/npu_integration.py @@ -322,7 +322,11 @@ async def offload_heavy_processing( except Exception as e: logger.error("Heavy processing offload failed: %s", e) - return {"success": False, "error": "Processing offload failed", "fallback": True} + return { + "success": False, + "error": "Processing offload failed", + "fallback": True, + } async def close(self): """No-op: HTTP client is managed by singleton HTTPClientManager""" diff --git a/autobot-backend/npu_semantic_search.py b/autobot-backend/npu_semantic_search.py index b12290a36..bd84a5921 100644 --- a/autobot-backend/npu_semantic_search.py +++ b/autobot-backend/npu_semantic_search.py @@ -860,7 +860,11 @@ async def _benchmark_single_device( except Exception as e: logger.error("❌ Benchmark failed for %s: %s", device.value, e) device_results.append( - {"query": query, "iteration": iteration, "error": "Benchmark failed"} + { + "query": query, + "iteration": iteration, + "error": "Benchmark failed", + } ) return device_results @@ -1344,7 +1348,10 @@ async def get_code_collection_stats(self) -> Dict[str, Any]: } except Exception as e: logger.error("Failed to get code collection stats: %s", e) - return {"available": False, "error": "Failed to retrieve code collection stats"} + return { + "available": False, + "error": "Failed to retrieve code collection stats", + } def _search_single_modality( self, diff --git a/autobot-backend/orchestration/execution_modes_test.py b/autobot-backend/orchestration/execution_modes_test.py index 2487e6bbb..98e6dc218 100644 --- a/autobot-backend/orchestration/execution_modes_test.py +++ b/autobot-backend/orchestration/execution_modes_test.py @@ -502,7 +502,9 @@ def test_dag_path_fires_send_workflow_notification(self) -> None: cfg = {"workflow_id": "wf_dag_notif", "channels": {}} mock_notify = unittest.mock.AsyncMock() - with unittest.mock.patch.object(executor, "_send_workflow_notification", mock_notify): + with unittest.mock.patch.object( + executor, "_send_workflow_notification", mock_notify + ): asyncio.get_event_loop().run_until_complete( executor.execute_coordinated_workflow( "wf_dag_notif", diff --git a/autobot-backend/orchestration/workflow_executor.py b/autobot-backend/orchestration/workflow_executor.py index c73792c7e..4c4ccb7c3 100644 --- a/autobot-backend/orchestration/workflow_executor.py +++ b/autobot-backend/orchestration/workflow_executor.py @@ -247,15 +247,16 @@ async def _send_workflow_notification( ) async def _send_step_failure_notification( - self, workflow_id: str, step_id: str, error: str, + self, + workflow_id: str, + step_id: str, + error: str, execution_context: Optional[Dict[str, Any]] = None, ) -> None: """Fire a STEP_FAILED notification (#3101, #3168).""" from services.notification_service import NotificationEvent - config = self._resolve_notification_config( - workflow_id, execution_context or {} - ) + config = self._resolve_notification_config(workflow_id, execution_context or {}) if config is None: return @@ -266,9 +267,7 @@ async def _send_step_failure_notification( "step_name": step_id, "error": error, } - await svc.send( - NotificationEvent.STEP_FAILED, workflow_id, payload, config - ) + await svc.send(NotificationEvent.STEP_FAILED, workflow_id, payload, config) except Exception: logger.warning( "Failed to send step-failure notification for %s/%s", @@ -649,7 +648,10 @@ async def execute_coordinated_workflow( workflow_id, ) return await self._execute_dag_workflow( - workflow_id, steps, effective_edges, context, + workflow_id, + steps, + effective_edges, + context, notification_config=notification_config, ) @@ -724,9 +726,7 @@ async def execute_coordinated_workflow( shared_memory.clear() # Issue #3101: fire notification on terminal status. - await self._send_workflow_notification( - workflow_id, execution_context - ) + await self._send_workflow_notification(workflow_id, execution_context) return execution_context @@ -735,9 +735,7 @@ async def execute_coordinated_workflow( execution_context["status"] = "failed" execution_context["error"] = str(e) # Issue #3101: fire failure notification. - await self._send_workflow_notification( - workflow_id, execution_context - ) + await self._send_workflow_notification(workflow_id, execution_context) return execution_context def _apply_checkpoints( diff --git a/autobot-backend/research_browser_manager.py b/autobot-backend/research_browser_manager.py index c13068d7a..58f6de2fb 100644 --- a/autobot-backend/research_browser_manager.py +++ b/autobot-backend/research_browser_manager.py @@ -335,7 +335,9 @@ async def extract_content(self) -> Dict[str, Any]: } except Exception as e: - logger.error("Content extraction failed for session %s: %s", self.session_id, e) + logger.error( + "Content extraction failed for session %s: %s", self.session_id, e + ) return {"success": False, "error": "Content extraction failed"} async def save_mhtml(self) -> Optional[str]: diff --git a/autobot-backend/security/domain_security_test.py b/autobot-backend/security/domain_security_test.py index 832beec3f..f23c539c9 100644 --- a/autobot-backend/security/domain_security_test.py +++ b/autobot-backend/security/domain_security_test.py @@ -176,7 +176,9 @@ def setup_method(self): ) def test_matches_with_content_between(self): - assert self.mgr._check_blacklist("pre-anything-fix.example.com")["blocked"] is True + assert ( + self.mgr._check_blacklist("pre-anything-fix.example.com")["blocked"] is True + ) def test_matches_when_wildcard_is_empty(self): assert self.mgr._check_blacklist("prefix.example.com")["blocked"] is True @@ -299,7 +301,9 @@ def setup_method(self): cfg = DomainSecurityConfig.__new__(DomainSecurityConfig) cfg.config_path = "" cfg.config = cfg._get_default_config() - with patch("security.domain_security.get_http_client", return_value=MagicMock()): + with patch( + "security.domain_security.get_http_client", return_value=MagicMock() + ): mgr = DomainSecurityManager.__new__(DomainSecurityManager) mgr.config = cfg mgr.domain_cache = {} diff --git a/autobot-backend/security/threat_intelligence.py b/autobot-backend/security/threat_intelligence.py index cfcad82d9..33579818e 100644 --- a/autobot-backend/security/threat_intelligence.py +++ b/autobot-backend/security/threat_intelligence.py @@ -286,7 +286,11 @@ async def _submit_url_for_analysis(self, url: str) -> Dict[str, Any]: } except Exception as e: logger.error("Failed to submit URL to VirusTotal: %s", e) - return {"success": False, "error": "VirusTotal submission failed", "score": None} + return { + "success": False, + "error": "VirusTotal submission failed", + "score": None, + } def _parse_url_response(self, data: Dict[str, Any]) -> Dict[str, Any]: """Parse VirusTotal URL analysis response.""" @@ -318,7 +322,11 @@ def _parse_url_response(self, data: Dict[str, Any]) -> Dict[str, Any]: } except Exception as e: logger.error("Failed to parse VirusTotal response: %s", e) - return {"success": False, "error": "Failed to parse VirusTotal response", "score": None} + return { + "success": False, + "error": "Failed to parse VirusTotal response", + "score": None, + } class URLVoidClient: @@ -418,7 +426,11 @@ async def check_domain(self, url: str) -> Dict[str, Any]: return {"success": False, "error": "Request timeout", "score": None} except Exception as e: logger.error("URLVoid API error: %s", e) - return {"success": False, "error": "URLVoid API request failed", "score": None} + return { + "success": False, + "error": "URLVoid API request failed", + "score": None, + } def _check_xml_error(self, root: Any) -> Optional[Dict[str, Any]]: """Check for error response in URLVoid XML. @@ -524,7 +536,11 @@ def _parse_response(self, content: str, domain: str) -> Dict[str, Any]: except Exception as e: # defusedxml raises various exceptions for malformed/malicious XML logger.error("Failed to parse URLVoid XML response: %s", e) - return {"success": False, "error": "Failed to parse URLVoid response", "score": None} + return { + "success": False, + "error": "Failed to parse URLVoid response", + "score": None, + } class ThreatIntelligenceService: diff --git a/autobot-backend/services/access_control_metrics.py b/autobot-backend/services/access_control_metrics.py index 4da83ebe1..1758a8f6e 100644 --- a/autobot-backend/services/access_control_metrics.py +++ b/autobot-backend/services/access_control_metrics.py @@ -273,7 +273,10 @@ async def get_statistics( except Exception as e: logger.error("Failed to get statistics: %s", e) - return {"error": "Failed to retrieve access control statistics", "total_violations": 0} + return { + "error": "Failed to retrieve access control statistics", + "total_violations": 0, + } def _parse_json_violation_data( self, @@ -404,7 +407,10 @@ async def get_endpoint_statistics(self, endpoint: str, days: int = 7) -> Metadat except Exception as e: logger.error("Failed to get endpoint statistics: %s", e) - return {"endpoint": endpoint, "error": "Failed to retrieve endpoint statistics"} + return { + "endpoint": endpoint, + "error": "Failed to retrieve endpoint statistics", + } async def get_user_statistics(self, username: str, days: int = 7) -> Metadata: """ diff --git a/autobot-backend/services/agent_terminal/service.py b/autobot-backend/services/agent_terminal/service.py index 15301f799..63ecf583f 100644 --- a/autobot-backend/services/agent_terminal/service.py +++ b/autobot-backend/services/agent_terminal/service.py @@ -817,7 +817,11 @@ async def execute_command( return await self._execute_auto_approved_command(session, command, risk) except Exception as e: logger.error("Command execution error: %s", e) - return {"status": "error", "error": "Command execution failed", "command": command} + return { + "status": "error", + "error": "Command execution failed", + "command": command, + } async def _save_command_to_chat( self, diff --git a/autobot-backend/services/autoresearch/archive.py b/autobot-backend/services/autoresearch/archive.py index 426ca1055..ddac2c80c 100644 --- a/autobot-backend/services/autoresearch/archive.py +++ b/autobot-backend/services/autoresearch/archive.py @@ -58,7 +58,9 @@ def _prune(self, max_size: int) -> None: # Selection # ------------------------------------------------------------------ - def select_parent(self, strategy: str = "random_weighted") -> Optional[VariantArchiveEntry]: + def select_parent( + self, strategy: str = "random_weighted" + ) -> Optional[VariantArchiveEntry]: """Return a parent entry using *strategy*. Supported strategies diff --git a/autobot-backend/services/autoresearch/config.py b/autobot-backend/services/autoresearch/config.py index bbdb911a7..c22efd916 100644 --- a/autobot-backend/services/autoresearch/config.py +++ b/autobot-backend/services/autoresearch/config.py @@ -87,9 +87,7 @@ class AutoResearchConfig: ) ) docker_memory_limit: str = field( - default_factory=lambda: os.getenv( - "AUTOBOT_AUTORESEARCH_DOCKER_MEMORY", "4g" - ) + default_factory=lambda: os.getenv("AUTOBOT_AUTORESEARCH_DOCKER_MEMORY", "4g") ) docker_cpu_limit: float = field( default_factory=lambda: float( @@ -114,9 +112,7 @@ class AutoResearchConfig: ) ) meta_agent_test_timeout: int = field( - default_factory=lambda: int( - os.getenv("AUTOBOT_META_AGENT_TEST_TIMEOUT", "60") - ) + default_factory=lambda: int(os.getenv("AUTOBOT_META_AGENT_TEST_TIMEOUT", "60")) ) meta_agent_approval_threshold: float = field( default_factory=lambda: float( diff --git a/autobot-backend/services/autoresearch/knowledge_synthesizer.py b/autobot-backend/services/autoresearch/knowledge_synthesizer.py index f96133b09..e9041c7ef 100644 --- a/autobot-backend/services/autoresearch/knowledge_synthesizer.py +++ b/autobot-backend/services/autoresearch/knowledge_synthesizer.py @@ -122,7 +122,9 @@ async def synthesize_session(self, session_id: str) -> List[ExperimentInsight]: ) raw_insights = json.loads(response.content) except json.JSONDecodeError as exc: - logger.warning("KnowledgeSynthesizer: failed to parse LLM response: %s", exc) + logger.warning( + "KnowledgeSynthesizer: failed to parse LLM response: %s", exc + ) return [] except Exception as exc: logger.exception("KnowledgeSynthesizer: LLM call failed: %s", exc) diff --git a/autobot-backend/services/autoresearch/knowledge_synthesizer_test.py b/autobot-backend/services/autoresearch/knowledge_synthesizer_test.py index a6a39b640..a6791f951 100644 --- a/autobot-backend/services/autoresearch/knowledge_synthesizer_test.py +++ b/autobot-backend/services/autoresearch/knowledge_synthesizer_test.py @@ -66,14 +66,16 @@ def mock_store(self): def mock_llm(self): llm = AsyncMock() mock_response = MagicMock() - mock_response.content = json.dumps([ - { - "statement": "Warmup steps >= 300 improve convergence", - "confidence": 0.8, - "supporting_experiments": ["e2"], - "related_hyperparams": ["warmup_steps"], - } - ]) + mock_response.content = json.dumps( + [ + { + "statement": "Warmup steps >= 300 improve convergence", + "confidence": 0.8, + "supporting_experiments": ["e2"], + "related_hyperparams": ["warmup_steps"], + } + ] + ) llm.chat.return_value = mock_response return llm @@ -106,12 +108,16 @@ async def test_query_insights(self, synthesizer, mock_chromadb): mock_chromadb.query.return_value = { "ids": [["i1"]], "documents": [["Warmup steps >= 300 improve convergence"]], - "metadatas": [[{ - "confidence": 0.8, - "supporting_experiments": "e2", - "related_hyperparams": "warmup_steps", - "session_id": "s1", - }]], + "metadatas": [ + [ + { + "confidence": 0.8, + "supporting_experiments": "e2", + "related_hyperparams": "warmup_steps", + "session_id": "s1", + } + ] + ], } results = await synthesizer.query_insights("warmup", limit=5) assert len(results) == 1 diff --git a/autobot-backend/services/autoresearch/prompt_optimizer.py b/autobot-backend/services/autoresearch/prompt_optimizer.py index b29fd9d34..5a89d813a 100644 --- a/autobot-backend/services/autoresearch/prompt_optimizer.py +++ b/autobot-backend/services/autoresearch/prompt_optimizer.py @@ -113,14 +113,16 @@ class OptimizationSession: def to_dict(self) -> Dict[str, Any]: return { "id": self.id, - "target": { - "agent_name": self.target.agent_name, - "scorer_chain": self.target.scorer_chain, - "mutation_count": self.target.mutation_count, - "top_k": self.target.top_k, - } - if self.target - else None, + "target": ( + { + "agent_name": self.target.agent_name, + "scorer_chain": self.target.scorer_chain, + "mutation_count": self.target.mutation_count, + "top_k": self.target.top_k, + } + if self.target + else None + ), "status": self.status.value, "rounds_completed": self.rounds_completed, "max_rounds": self.max_rounds, @@ -361,9 +363,7 @@ async def _score_through_chain( ) continue - subset_frac = ( - self._config.staged_eval_fraction if tier_idx == 0 else None - ) + subset_frac = self._config.staged_eval_fraction if tier_idx == 0 else None candidates, tier_failed = await self._score_tier( scorer=scorer, scorer_name=scorer_name, @@ -417,9 +417,7 @@ async def _score_tier( subset_fraction=subset_fraction, ) variant.scores[scorer_name] = result.score - variant.final_score = ( - sum(variant.scores.values()) / len(variant.scores) - ) + variant.final_score = sum(variant.scores.values()) / len(variant.scores) except Exception as exc: logger.warning( "PromptOptimizer: scorer %r failed for variant %s: %s", diff --git a/autobot-backend/services/autoresearch/prompt_optimizer_test.py b/autobot-backend/services/autoresearch/prompt_optimizer_test.py index 0744e405b..c093501e0 100644 --- a/autobot-backend/services/autoresearch/prompt_optimizer_test.py +++ b/autobot-backend/services/autoresearch/prompt_optimizer_test.py @@ -22,11 +22,11 @@ ) from services.autoresearch.scorers import ScorerResult - # --------------------------------------------------------------------------- # Helper factory # --------------------------------------------------------------------------- + def _make_variant(vid: str, score: float, round_number: int = 1) -> PromptVariant: return PromptVariant( id=vid, @@ -58,6 +58,7 @@ def _make_entry( # PromptVariant # --------------------------------------------------------------------------- + class TestPromptVariantModel: def test_to_dict(self): variant = PromptVariant( @@ -85,6 +86,7 @@ def test_from_dict_round_trip(self): # OptimizationSession # --------------------------------------------------------------------------- + class TestOptimizationSession: def test_to_dict(self): target = PromptOptTarget( @@ -105,6 +107,7 @@ def test_to_dict(self): # Archive unit tests # --------------------------------------------------------------------------- + class TestArchive: def test_add_retains_all_entries(self): archive = Archive() @@ -184,6 +187,7 @@ def test_serialisation_round_trip(self): # PromptOptimizer integration (archive-aware) # --------------------------------------------------------------------------- + class TestPromptOptimizerLoop: @pytest.fixture def mock_llm(self): @@ -198,9 +202,15 @@ def mock_scorer(self): scorer = AsyncMock() scorer.name = "test_scorer" scorer.score.side_effect = [ - ScorerResult(score=0.3, raw_score=3, metadata={}, scorer_name="test_scorer"), - ScorerResult(score=0.8, raw_score=8, metadata={}, scorer_name="test_scorer"), - ScorerResult(score=0.5, raw_score=5, metadata={}, scorer_name="test_scorer"), + ScorerResult( + score=0.3, raw_score=3, metadata={}, scorer_name="test_scorer" + ), + ScorerResult( + score=0.8, raw_score=8, metadata={}, scorer_name="test_scorer" + ), + ScorerResult( + score=0.5, raw_score=5, metadata={}, scorer_name="test_scorer" + ), ] return scorer @@ -406,9 +416,7 @@ async def benchmark_fn(prompt: str) -> str: assert session.rounds_completed == 0 @pytest.mark.asyncio - async def test_scorer_failure_marks_variant_invalid_in_archive( - self, mock_llm - ): + async def test_scorer_failure_marks_variant_invalid_in_archive(self, mock_llm): """Variants whose scorer raises must have valid_parent=False in archive.""" failing_scorer = AsyncMock() failing_scorer.score.side_effect = RuntimeError("scorer exploded") diff --git a/autobot-backend/services/autoresearch/routes.py b/autobot-backend/services/autoresearch/routes.py index f3dd198f3..92b781cb2 100644 --- a/autobot-backend/services/autoresearch/routes.py +++ b/autobot-backend/services/autoresearch/routes.py @@ -361,7 +361,9 @@ async def submit_variant_score( # Validate key components to prevent Redis key injection if not _UUID_PATTERN.match(session_id) or not _UUID_PATTERN.match(variant_id): - raise HTTPException(status_code=400, detail="Invalid session_id or variant_id format") + raise HTTPException( + status_code=400, detail="Invalid session_id or variant_id format" + ) redis = get_redis_client(async_client=True, database="main") key = f"autoresearch:prompt_review:{session_id}:{variant_id}" @@ -395,13 +397,13 @@ async def list_pending_approvals( key_str = key if isinstance(key, str) else key.decode("utf-8") parts = key_str.split(":") if len(parts) >= 5: - status_key = ( - f"autoresearch:approval:status:{parts[3]}:{parts[4]}" - ) + status_key = f"autoresearch:approval:status:{parts[3]}:{parts[4]}" status = await redis.get(status_key) status_str = ( - status.decode("utf-8") if isinstance(status, bytes) else status - ) if status else "unknown" + (status.decode("utf-8") if isinstance(status, bytes) else status) + if status + else "unknown" + ) if status_str == "pending": data["status"] = "pending" approvals.append(data) diff --git a/autobot-backend/services/autoresearch/run_experiment.py b/autobot-backend/services/autoresearch/run_experiment.py index 5fe2f6d19..e8beaac93 100644 --- a/autobot-backend/services/autoresearch/run_experiment.py +++ b/autobot-backend/services/autoresearch/run_experiment.py @@ -52,7 +52,7 @@ def _build_train_args() -> list[str]: args.append(f"--{flag}={value}") for key, value in os.environ.items(): if key.startswith(_EXTRA_PREFIX): - flag = key[len(_EXTRA_PREFIX):].lower() + flag = key[len(_EXTRA_PREFIX) :].lower() args.append(f"--{flag}={value}") return args diff --git a/autobot-backend/services/autoresearch/runner.py b/autobot-backend/services/autoresearch/runner.py index a7b78b111..89c20759d 100644 --- a/autobot-backend/services/autoresearch/runner.py +++ b/autobot-backend/services/autoresearch/runner.py @@ -261,9 +261,7 @@ def _validate_mount_path(path: Path) -> None: """Reject obviously unsafe mount paths (root or non-absolute).""" resolved = path.resolve() if not resolved.is_absolute() or resolved == Path("/"): - raise ValueError( - f"autoresearch_dir is unsafe to mount: {path}" - ) + raise ValueError(f"autoresearch_dir is unsafe to mount: {path}") @staticmethod def _build_docker_env_flags(hp: object) -> list[str]: diff --git a/autobot-backend/services/autoresearch/runner_test.py b/autobot-backend/services/autoresearch/runner_test.py index 162d90103..4e7d0f307 100644 --- a/autobot-backend/services/autoresearch/runner_test.py +++ b/autobot-backend/services/autoresearch/runner_test.py @@ -749,6 +749,7 @@ def test_container_name_flag_present(self): def test_unsafe_mount_path_raises(self): from pathlib import Path + runner = _make_runner() with pytest.raises(ValueError, match="unsafe"): runner._validate_mount_path(Path("/")) @@ -851,9 +852,7 @@ def __enter__(self): with open( os.path.join(path, "result.json"), "w", encoding="utf-8" ) as fh: - json.dump( - {"returncode": 0, "stdout": "", "stderr": ""}, fh - ) + json.dump({"returncode": 0, "stdout": "", "stderr": ""}, fh) return path def __exit__(self, *args): diff --git a/autobot-backend/services/autoresearch/scorers.py b/autobot-backend/services/autoresearch/scorers.py index d520491f8..6314aa6ed 100644 --- a/autobot-backend/services/autoresearch/scorers.py +++ b/autobot-backend/services/autoresearch/scorers.py @@ -94,7 +94,9 @@ def __init__( baseline_val_bpb: float, ) -> None: if baseline_val_bpb <= 0: - raise ValueError(f"baseline_val_bpb must be positive, got {baseline_val_bpb}") + raise ValueError( + f"baseline_val_bpb must be positive, got {baseline_val_bpb}" + ) self._runner = runner self._baseline = baseline_val_bpb @@ -148,7 +150,9 @@ async def score( # Normalize: improvement as fraction of baseline, clamped 0-1 improvement = self._baseline - val_bpb - normalized = max(0.0, improvement / self._baseline) if self._baseline > 0 else 0.0 + normalized = ( + max(0.0, improvement / self._baseline) if self._baseline > 0 else 0.0 + ) return ScorerResult( score=normalized, @@ -167,7 +171,7 @@ async def score( _JUDGE_SYSTEM_PROMPT = ( "You are a prompt quality evaluator. Rate the following output on a scale " "of 0-10 based on these criteria: {criteria}.\n\n" - "Respond with JSON: {{\"rating\": <0-10>, \"reasoning\": \"\"}}" + 'Respond with JSON: {{"rating": <0-10>, "reasoning": ""}}' ) @@ -311,11 +315,13 @@ async def score( ) await redis.set( pending_key, - json.dumps({ - "prompt_output": prompt_output[:5000], - "session_id": session_id, - "variant_id": variant_id, - }), + json.dumps( + { + "prompt_output": prompt_output[:5000], + "session_id": session_id, + "variant_id": variant_id, + } + ), ex=self._TTL_SECONDS, ) diff --git a/autobot-backend/services/autoresearch/store.py b/autobot-backend/services/autoresearch/store.py index 47ce6f51c..e53997100 100644 --- a/autobot-backend/services/autoresearch/store.py +++ b/autobot-backend/services/autoresearch/store.py @@ -136,7 +136,9 @@ def _build_document(self, experiment: Experiment) -> str: ] # Include hyperparams for richer search hp_dict = experiment.hyperparams.to_dict() - parts.append(f"Hyperparams: {', '.join(f'{k}={v}' for k, v in hp_dict.items())}") + parts.append( + f"Hyperparams: {', '.join(f'{k}={v}' for k, v in hp_dict.items())}" + ) if experiment.result: parts.append(f"val_bpb: {experiment.result.val_bpb}") diff --git a/autobot-backend/services/captcha_human_loop.py b/autobot-backend/services/captcha_human_loop.py index 251c41f89..edbe2b15c 100644 --- a/autobot-backend/services/captcha_human_loop.py +++ b/autobot-backend/services/captcha_human_loop.py @@ -464,7 +464,9 @@ async def request_human_intervention( except Exception as e: logger.error("Error requesting CAPTCHA intervention: %s", e) - return self._build_error_result(captcha_id, url, start_time, "CAPTCHA intervention request failed") + return self._build_error_result( + captcha_id, url, start_time, "CAPTCHA intervention request failed" + ) finally: self._cleanup_captcha_tracking(captcha_id) diff --git a/autobot-backend/services/conversation_export.py b/autobot-backend/services/conversation_export.py index 3a2dbd1b9..9b175ee1f 100644 --- a/autobot-backend/services/conversation_export.py +++ b/autobot-backend/services/conversation_export.py @@ -62,9 +62,7 @@ def _render_session_metadata_markdown( # --------------------------------------------------------------------------- -def _build_json_envelope( - session_id: str, chat_data: Dict[str, Any] -) -> Dict[str, Any]: +def _build_json_envelope(session_id: str, chat_data: Dict[str, Any]) -> Dict[str, Any]: """Wrap raw session data in the versioned AutoBot JSON export envelope.""" return { "format": AUTOBOT_EXPORT_FORMAT, @@ -150,9 +148,7 @@ async def export_all_conversations_json(chat_history_manager) -> Optional[str]: session_id = session_info.get("chatId") or session_info.get("id", "") if not session_id: continue - chat_data = await _load_full_session_data( - chat_history_manager, session_id - ) + chat_data = await _load_full_session_data(chat_history_manager, session_id) if chat_data is not None: envelopes.append(_build_json_envelope(session_id, chat_data)) archive = _build_bulk_envelope(envelopes) diff --git a/autobot-backend/services/fact_extraction_service.py b/autobot-backend/services/fact_extraction_service.py index e051bf05c..1bdd20a88 100644 --- a/autobot-backend/services/fact_extraction_service.py +++ b/autobot-backend/services/fact_extraction_service.py @@ -339,7 +339,9 @@ async def extract_facts_from_chunks( except Exception as e: logger.error("Error processing chunks for fact extraction: %s", e) - return self._build_chunks_error_response("Chunk fact extraction failed", len(chunks)) + return self._build_chunks_error_response( + "Chunk fact extraction failed", len(chunks) + ) async def _deduplicate_facts(self, facts: List[AtomicFact]) -> List[AtomicFact]: """ diff --git a/autobot-backend/services/feature_flags.py b/autobot-backend/services/feature_flags.py index a7c9bb81f..a7c00f5ed 100644 --- a/autobot-backend/services/feature_flags.py +++ b/autobot-backend/services/feature_flags.py @@ -324,7 +324,10 @@ async def get_rollout_statistics(self) -> Metadata: except Exception as e: logger.error("Failed to get rollout statistics: %s", e) - return {"error": "Failed to retrieve rollout statistics", "current_mode": "unknown"} + return { + "error": "Failed to retrieve rollout statistics", + "current_mode": "unknown", + } async def clear_all_flags(self) -> bool: """ diff --git a/autobot-backend/services/knowledge/doc_indexer.py b/autobot-backend/services/knowledge/doc_indexer.py index 9eb00d895..5bf43163a 100644 --- a/autobot-backend/services/knowledge/doc_indexer.py +++ b/autobot-backend/services/knowledge/doc_indexer.py @@ -221,7 +221,7 @@ def _parse_frontmatter(content: str) -> Tuple[str, List[str], List[str]]: return content, [], [] fm_block = content[3:end] - body = content[end + 4:].lstrip("\n") + body = content[end + 4 :].lstrip("\n") fm_tags: List[str] = [] fm_aliases: List[str] = [] @@ -232,7 +232,7 @@ def _parse_frontmatter(content: str) -> Tuple[str, List[str], List[str]]: key_match = re.match(r"^(\w+)\s*:", line) if key_match: current_key = key_match.group(1) - inline = line[key_match.end():].strip() + inline = line[key_match.end() :].strip() if inline and current_key in ("tags", "aliases"): target = fm_tags if current_key == "tags" else fm_aliases target.append(inline.lstrip("- ").strip()) diff --git a/autobot-backend/services/llm_cost_tracker.py b/autobot-backend/services/llm_cost_tracker.py index 4238e8c56..fccbc02b5 100644 --- a/autobot-backend/services/llm_cost_tracker.py +++ b/autobot-backend/services/llm_cost_tracker.py @@ -858,7 +858,10 @@ async def get_cost_by_session(self, session_id: str) -> Dict[str, Any]: except Exception as e: logger.error("Failed to get session cost: %s", e) - return {"session_id": session_id, "error": "Failed to retrieve session cost"} + return { + "session_id": session_id, + "error": "Failed to retrieve session cost", + } async def get_cost_trends(self, days: int = 30) -> Dict[str, Any]: """ diff --git a/autobot-backend/services/llm_service.py b/autobot-backend/services/llm_service.py index 46930d849..12e5ecd67 100644 --- a/autobot-backend/services/llm_service.py +++ b/autobot-backend/services/llm_service.py @@ -81,7 +81,9 @@ def _apply_task_defaults( """ defaults = _TASK_TYPE_DEFAULTS.get(llm_type.value, _TASK_TYPE_DEFAULTS["general"]) resolved_temp = temperature if temperature is not None else defaults["temperature"] - resolved_tokens = max_tokens if max_tokens is not None else defaults.get("max_tokens") + resolved_tokens = ( + max_tokens if max_tokens is not None else defaults.get("max_tokens") + ) return resolved_temp, resolved_tokens @@ -182,9 +184,7 @@ async def chat( if provider is None: self._error_count += 1 logger.error("No available provider for chat request") - return _build_error_response( - request, "No available LLM provider", "none" - ) + return _build_error_response(request, "No available LLM provider", "none") response = await provider.chat_completion(request) if response.error: @@ -275,9 +275,7 @@ async def list_models( import asyncio as _asyncio target_names = ( - [provider_name] - if provider_name - else list(self._registry._providers.keys()) + [provider_name] if provider_name else list(self._registry._providers.keys()) ) results: Dict[str, List[str]] = {} for name in target_names: diff --git a/autobot-backend/services/playwright_service.py b/autobot-backend/services/playwright_service.py index f7aee1643..a42f20dbb 100644 --- a/autobot-backend/services/playwright_service.py +++ b/autobot-backend/services/playwright_service.py @@ -198,7 +198,12 @@ async def search_web( } except Exception as e: logger.error("Web search error: %s", e) - return {"success": False, "error": "Web search failed", "query": query, "results": []} + return { + "success": False, + "error": "Web search failed", + "query": query, + "results": [], + } async def test_frontend( self, frontend_url: str = ServiceURLs.FRONTEND_LOCAL @@ -317,7 +322,12 @@ async def send_test_message( } except Exception as e: logger.error("Test message error: %s", e) - return {"success": False, "error": "Test message failed", "message": message, "steps": []} + return { + "success": False, + "error": "Test message failed", + "message": message, + "steps": [], + } async def capture_screenshot( self, url: str, full_page: bool = True, wait_timeout: int = 5000 diff --git a/autobot-backend/services/redis_service_manager.py b/autobot-backend/services/redis_service_manager.py index 8cd8f566d..faaf0d5ca 100644 --- a/autobot-backend/services/redis_service_manager.py +++ b/autobot-backend/services/redis_service_manager.py @@ -364,9 +364,13 @@ async def start_service(self, user_id: str = "system") -> ServiceOperationResult logger.error("Start service failed: %s", e) await self._record_error() self._audit_log( - "redis_service_start_failed", {"error": type(e).__name__}, user_id=user_id + "redis_service_start_failed", + {"error": type(e).__name__}, + user_id=user_id, + ) + return self._operation_failure_result( + "start", "Service start failed", duration ) - return self._operation_failure_result("start", "Service start failed", duration) async def stop_service(self, user_id: str = "system") -> ServiceOperationResult: """ @@ -428,9 +432,13 @@ async def stop_service(self, user_id: str = "system") -> ServiceOperationResult: logger.error("Stop service failed: %s", e) await self._record_error() self._audit_log( - "redis_service_stop_failed", {"error": type(e).__name__}, user_id=user_id + "redis_service_stop_failed", + {"error": type(e).__name__}, + user_id=user_id, + ) + return self._operation_failure_result( + "stop", "Service stop failed", duration ) - return self._operation_failure_result("stop", "Service stop failed", duration) async def restart_service(self, user_id: str = "system") -> ServiceOperationResult: """ @@ -483,9 +491,13 @@ async def restart_service(self, user_id: str = "system") -> ServiceOperationResu logger.error("Restart service failed: %s", e) await self._record_error() self._audit_log( - "redis_service_restart_failed", {"error": type(e).__name__}, user_id=user_id + "redis_service_restart_failed", + {"error": type(e).__name__}, + user_id=user_id, + ) + return self._operation_failure_result( + "restart", "Service restart failed", duration ) - return self._operation_failure_result("restart", "Service restart failed", duration) async def get_service_status(self, use_cache: bool = True) -> ServiceStatus: """ diff --git a/autobot-backend/services/semantic_analyzer.py b/autobot-backend/services/semantic_analyzer.py index 793c289ba..8cb3ba7d2 100644 --- a/autobot-backend/services/semantic_analyzer.py +++ b/autobot-backend/services/semantic_analyzer.py @@ -54,7 +54,9 @@ class SemanticAnalyzer: "docstring": re.compile(r'"""[\s\S]{0,5000}Args:[\s\S]{0,5000}Returns:'), }, "numpy": { - "docstring": re.compile(r'"""[\s\S]{0,5000}Parameters[\s\S]{0,5000}----------'), + "docstring": re.compile( + r'"""[\s\S]{0,5000}Parameters[\s\S]{0,5000}----------' + ), }, } diff --git a/autobot-backend/services/temporal_invalidation_service.py b/autobot-backend/services/temporal_invalidation_service.py index 43af20077..52a99b9b0 100644 --- a/autobot-backend/services/temporal_invalidation_service.py +++ b/autobot-backend/services/temporal_invalidation_service.py @@ -258,7 +258,10 @@ async def initialize_rules(self) -> Dict[str, Any]: except Exception as e: logger.error("Error initializing invalidation rules: %s", e) - return {"status": "error", "message": "Temporal invalidation operation failed"} + return { + "status": "error", + "message": "Temporal invalidation operation failed", + } async def _load_invalidation_rules(self) -> Dict[str, InvalidationRule]: """Load invalidation rules from Redis.""" @@ -638,7 +641,9 @@ async def run_invalidation_sweep( except Exception as e: logger.error("Error in invalidation sweep: %s", e) processing_time = (datetime.now() - start_time).total_seconds() - return self._build_sweep_error_response("Invalidation sweep failed", processing_time) + return self._build_sweep_error_response( + "Invalidation sweep failed", processing_time + ) def _prepare_fact_for_invalidation( self, pipe, fact: AtomicFact, reasons: Dict[str, Dict[str, Any]] @@ -869,7 +874,10 @@ async def invalidate_contradictory_facts( except Exception as e: logger.error("Error in contradiction invalidation: %s", e) - return {"status": "error", "message": "Temporal invalidation operation failed"} + return { + "status": "error", + "message": "Temporal invalidation operation failed", + } def _aggregate_history_statistics( self, recent_history: List[str] @@ -969,7 +977,10 @@ async def add_invalidation_rule(self, rule: InvalidationRule) -> Dict[str, Any]: except Exception as e: logger.error("Error adding invalidation rule: %s", e) - return {"status": "error", "message": "Temporal invalidation operation failed"} + return { + "status": "error", + "message": "Temporal invalidation operation failed", + } async def remove_invalidation_rule(self, rule_id: str) -> Dict[str, Any]: """Remove an invalidation rule.""" @@ -985,7 +996,10 @@ async def remove_invalidation_rule(self, rule_id: str) -> Dict[str, Any]: except Exception as e: logger.error("Error removing invalidation rule: %s", e) - return {"status": "error", "message": "Temporal invalidation operation failed"} + return { + "status": "error", + "message": "Temporal invalidation operation failed", + } async def schedule_periodic_invalidation(self): """Schedule periodic invalidation sweeps.""" diff --git a/autobot-backend/services/terminal_secrets_service.py b/autobot-backend/services/terminal_secrets_service.py index 11a90ccae..601a830a6 100644 --- a/autobot-backend/services/terminal_secrets_service.py +++ b/autobot-backend/services/terminal_secrets_service.py @@ -164,7 +164,6 @@ async def _prepare_session_keys( logger.error("Failed to prepare key '%s': %s", key_data["name"], e) result["errors"].append(f"Failed to prepare key '{key_data['name']}'") - async def setup_ssh_keys( self, session_id: str, diff --git a/autobot-backend/services/user_behavior_analytics.py b/autobot-backend/services/user_behavior_analytics.py index fbf7ff53a..b0599d39c 100644 --- a/autobot-backend/services/user_behavior_analytics.py +++ b/autobot-backend/services/user_behavior_analytics.py @@ -271,7 +271,11 @@ async def get_user_journey(self, session_id: str) -> dict: except Exception as e: logger.error("Failed to get user journey: %s", e) - return {"session_id": session_id, "error": "Failed to retrieve user journey", "steps": []} + return { + "session_id": session_id, + "error": "Failed to retrieve user journey", + "steps": [], + } async def get_daily_stats(self, days: int = 30) -> dict: """ diff --git a/autobot-backend/services/workflow_automation/executor.py b/autobot-backend/services/workflow_automation/executor.py index 45a76091b..ddfa753c8 100644 --- a/autobot-backend/services/workflow_automation/executor.py +++ b/autobot-backend/services/workflow_automation/executor.py @@ -402,9 +402,13 @@ async def _send_step_confirmation_request( # Issue #3101: Notify configured channels that approval is needed. if step.requires_confirmation: - await self._notify(workflow, "approval_needed", { - "step_name": step.step_id, - }) + await self._notify( + workflow, + "approval_needed", + { + "step_name": step.step_id, + }, + ) def _check_step_dependencies( self, workflow: ActiveWorkflow, step: WorkflowStep @@ -531,10 +535,14 @@ async def _handle_step_execution_failure( ) # Issue #3101: Notify configured channels on step failure. - await self._notify(workflow, "step_failed", { - "step_name": step_id, - "error": str(error), - }) + await self._notify( + workflow, + "step_failed", + { + "step_name": step_id, + "error": str(error), + }, + ) async def approve_and_execute_step( self, @@ -776,10 +784,14 @@ async def _complete_workflow( ) # Issue #3101: Notify configured channels on workflow completion. - await self._notify(workflow, "workflow_completed", { - "status": "completed", - "total_steps": len(workflow.steps), - }) + await self._notify( + workflow, + "workflow_completed", + { + "status": "completed", + "total_steps": len(workflow.steps), + }, + ) # Issue #1367: Archive to completed history if self.on_workflow_finished: @@ -839,9 +851,13 @@ async def cancel_workflow( ) # Issue #3101: Notify configured channels on workflow cancellation/failure. - await self._notify(workflow, "workflow_failed", { - "error": "cancelled", - }) + await self._notify( + workflow, + "workflow_failed", + { + "error": "cancelled", + }, + ) # Issue #1367: Archive to completed history if self.on_workflow_finished: diff --git a/autobot-backend/services/workflow_automation/models.py b/autobot-backend/services/workflow_automation/models.py index 37926fe09..007140dad 100644 --- a/autobot-backend/services/workflow_automation/models.py +++ b/autobot-backend/services/workflow_automation/models.py @@ -311,11 +311,26 @@ class PlanPresentationRequest(BaseModel): _EMAIL_RE = __import__("re").compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$") _PRIVATE_PREFIXES = ( - "https://10.", "https://172.16.", "https://172.17.", "https://172.18.", - "https://172.19.", "https://172.20.", "https://172.21.", "https://172.22.", - "https://172.23.", "https://172.24.", "https://172.25.", "https://172.26.", - "https://172.27.", "https://172.28.", "https://172.29.", "https://172.30.", - "https://172.31.", "https://192.168.", "https://127.", "https://169.254.", + "https://10.", + "https://172.16.", + "https://172.17.", + "https://172.18.", + "https://172.19.", + "https://172.20.", + "https://172.21.", + "https://172.22.", + "https://172.23.", + "https://172.24.", + "https://172.25.", + "https://172.26.", + "https://172.27.", + "https://172.28.", + "https://172.29.", + "https://172.30.", + "https://172.31.", + "https://192.168.", + "https://127.", + "https://169.254.", "https://localhost", ) diff --git a/autobot-backend/services/workflow_automation/persistence.py b/autobot-backend/services/workflow_automation/persistence.py index 8e8722163..091b72d66 100644 --- a/autobot-backend/services/workflow_automation/persistence.py +++ b/autobot-backend/services/workflow_automation/persistence.py @@ -44,7 +44,9 @@ async def save_notification_config( key = _notif_config_key(workflow_id) if config is None: await redis.delete(key) - logger.debug("Deleted notification config from Redis (workflow=%s)", workflow_id) + logger.debug( + "Deleted notification config from Redis (workflow=%s)", workflow_id + ) return payload = json.dumps(asdict(config), ensure_ascii=False) await redis.set(key, payload, ex=_NOTIF_CONFIG_TTL) diff --git a/autobot-backend/startup_validator.py b/autobot-backend/startup_validator.py index be3c68167..07c50249e 100644 --- a/autobot-backend/startup_validator.py +++ b/autobot-backend/startup_validator.py @@ -185,7 +185,9 @@ def _validate_autobot_modules(self): ) except Exception as e: # Module imported but failed to initialize - logger.error("AutoBot module initialization failed: %s: %s", module_name, e) + logger.error( + "AutoBot module initialization failed: %s: %s", module_name, e + ) self.result.add_error( f"AutoBot module initialization failed: {module_name}", {"error": type(e).__name__}, @@ -202,10 +204,13 @@ def _validate_optional_modules(self): except ImportError as e: logger.debug("Optional module not available: %s: %s", module_name, e) self.result.add_warning( - f"Optional module not available: {module_name}", {"error": type(e).__name__} + f"Optional module not available: {module_name}", + {"error": type(e).__name__}, ) except Exception as e: - logger.debug("Optional module initialization failed: %s: %s", module_name, e) + logger.debug( + "Optional module initialization failed: %s: %s", module_name, e + ) self.result.add_warning( f"Optional module initialization failed: {module_name}", {"error": type(e).__name__}, @@ -253,7 +258,9 @@ async def validate_single_service(service_name: str, validator_func): logger.debug("✅ Service connectivity: %s", service_name) return service_name, None except Exception as e: - logger.error("Service connectivity check failed for %s: %s", service_name, e) + logger.error( + "Service connectivity check failed for %s: %s", service_name, e + ) return service_name, "Service connectivity check failed" results = await asyncio.gather( diff --git a/autobot-backend/takeover_manager.e2e_test.py b/autobot-backend/takeover_manager.e2e_test.py index 62a52c3ce..4d3f74d42 100644 --- a/autobot-backend/takeover_manager.e2e_test.py +++ b/autobot-backend/takeover_manager.e2e_test.py @@ -67,7 +67,11 @@ async def run_all_tests(self): except Exception as e: logger.error(f"❌ {test_method.__name__} FAILED: {e}") self.test_results.append( - {"test": test_method.__name__, "status": "FAILED", "error": "Test execution failed"} + { + "test": test_method.__name__, + "status": "FAILED", + "error": "Test execution failed", + } ) await self.print_test_summary() diff --git a/autobot-backend/takeover_manager.py b/autobot-backend/takeover_manager.py index 54d66e018..0de6eae7e 100644 --- a/autobot-backend/takeover_manager.py +++ b/autobot-backend/takeover_manager.py @@ -597,7 +597,10 @@ async def _capture_system_snapshot(self) -> Dict[str, Any]: except Exception as e: logger.error("Failed to capture system snapshot: %s", e) - return {"error": "Failed to capture system snapshot", "timestamp": datetime.now().isoformat()} + return { + "error": "Failed to capture system snapshot", + "timestamp": datetime.now().isoformat(), + } async def _execute_trigger_handlers(self, request: TakeoverRequest): """Execute registered handlers for takeover triggers""" diff --git a/autobot-backend/tests/utils/test_cache_response_json_response.py b/autobot-backend/tests/utils/test_cache_response_json_response.py index 1d8fe3f44..d3b658290 100644 --- a/autobot-backend/tests/utils/test_cache_response_json_response.py +++ b/autobot-backend/tests/utils/test_cache_response_json_response.py @@ -28,7 +28,6 @@ ) from utils.advanced_cache_manager import SimpleCacheManager - # --------------------------------------------------------------------------- # _serialise_response # --------------------------------------------------------------------------- diff --git a/autobot-backend/tools/terminal_tool.py b/autobot-backend/tools/terminal_tool.py index 3b6d381cf..7aa20f5b0 100644 --- a/autobot-backend/tools/terminal_tool.py +++ b/autobot-backend/tools/terminal_tool.py @@ -210,7 +210,11 @@ async def execute_command( return self._format_execution_result(result, command, description) except Exception as e: logger.error("Error executing command: %s", e, exc_info=True) - return {"status": "error", "error": "Command execution failed", "command": command} + return { + "status": "error", + "error": "Command execution failed", + "command": command, + } async def get_session_info(self, conversation_id: str) -> Dict[str, Any]: """ diff --git a/autobot-backend/utils/gpu_acceleration_optimizer.py b/autobot-backend/utils/gpu_acceleration_optimizer.py index d4b60f89e..6fb3e1781 100644 --- a/autobot-backend/utils/gpu_acceleration_optimizer.py +++ b/autobot-backend/utils/gpu_acceleration_optimizer.py @@ -224,7 +224,9 @@ async def optimize_for_multimodal_workload(self) -> GPUOptimizationResult: except Exception as e: self.logger.error("Multi-modal optimization failed: %s", e) - return GPUOptimizationResult.create_failed("multimodal_workload", "Multi-modal optimization failed") + return GPUOptimizationResult.create_failed( + "multimodal_workload", "Multi-modal optimization failed" + ) async def _collect_performance_baseline(self) -> Dict[str, float]: """Collect current performance metrics as baseline.""" diff --git a/autobot-frontend/src/components/knowledge/KnowledgeGraph3D.vue b/autobot-frontend/src/components/knowledge/KnowledgeGraph3D.vue index 7c5bf7904..3c1618929 100644 --- a/autobot-frontend/src/components/knowledge/KnowledgeGraph3D.vue +++ b/autobot-frontend/src/components/knowledge/KnowledgeGraph3D.vue @@ -93,6 +93,8 @@ const container = ref(null) // Issue #704 pattern: same rationale as KnowledgeGraph.vue shallowRef // Issue #3363: typed with ForceGraph3DInstance instead of any const graph = shallowRef(null) +// Issue #3370: ResizeObserver tracks container size changes; disconnected in disposeGraph() +let resizeObserver: ResizeObserver | null = null const isEmpty = computed(() => props.entities.length === 0) @@ -191,6 +193,16 @@ function initGraph(): void { emit('entity-selected', null) }) + // Issue #3370: update canvas dimensions whenever the container resizes + resizeObserver = new ResizeObserver((entries) => { + const rect = entries[0]?.contentRect + if (graph.value && rect) { + graph.value.width(Math.floor(rect.width)).height(Math.floor(rect.height)) + logger.debug('3D graph resized', { width: Math.floor(rect.width), height: Math.floor(rect.height) }) + } + }) + resizeObserver.observe(container.value) + logger.debug('3D graph initialized', { nodes: props.entities.length, links: props.edges.length }) } @@ -199,6 +211,12 @@ function initGraph(): void { * Issue #3363: renderer.dispose() alone does not release geometry/material buffers. */ function disposeGraph(): void { + // Issue #3370: disconnect before tearing down the graph to avoid stale callbacks + if (resizeObserver) { + resizeObserver.disconnect() + resizeObserver = null + } + if (!graph.value) return graph.value.pauseAnimation() diff --git a/autobot-slm-backend/api/updates.py b/autobot-slm-backend/api/updates.py index 43f3445fd..c83ef19cb 100644 --- a/autobot-slm-backend/api/updates.py +++ b/autobot-slm-backend/api/updates.py @@ -283,7 +283,9 @@ async def _run_update_job(job_id: str, node_id: str, update_ids: List[str]) -> N job.error = "Internal server error" job.completed_at = datetime.utcnow() await db.commit() - await _broadcast_job_update(job_id, "failed", job.progress, "Update job failed") + await _broadcast_job_update( + job_id, "failed", job.progress, "Update job failed" + ) def _parse_discover_output(output: str) -> List[dict]: @@ -638,7 +640,9 @@ async def _run_discover_job( job["status"] = "failed" job["message"] = "Discover job failed" job["completed_at"] = datetime.utcnow().isoformat() - await _broadcast_job_update(job_id, "failed", job.get("progress", 0), "Discover job failed") + await _broadcast_job_update( + job_id, "failed", job.get("progress", 0), "Discover job failed" + ) @router.post("/discover", response_model=UpdateDiscoverResponse) diff --git a/autobot-slm-backend/monitoring/performance_dashboard.py b/autobot-slm-backend/monitoring/performance_dashboard.py index 4a88f1b15..6647a3a80 100644 --- a/autobot-slm-backend/monitoring/performance_dashboard.py +++ b/autobot-slm-backend/monitoring/performance_dashboard.py @@ -568,7 +568,9 @@ async def get_metrics_history(self, request): except Exception as e: logger.error("Error getting metrics history: %s", e) - return web.json_response({"error": "Internal server error", "history": []}, status=500) + return web.json_response( + {"error": "Internal server error", "history": []}, status=500 + ) async def get_system_status(self, request): """Get overall system status summary."""