From 107ae7286284b463997277e77036b8e317e16824 Mon Sep 17 00:00:00 2001 From: mrveiss Date: Fri, 3 Apr 2026 23:01:53 +0300 Subject: [PATCH 1/2] style: apply Black formatting to 89 Python files --- autobot-backend/agents/base_agent.py | 5 ++- .../agents/knowledge_retrieval_agent.py | 6 ++- autobot-backend/agents/librarian_assistant.py | 4 +- .../agents/npu_code_search_agent.py | 6 ++- .../agents/system_knowledge_manager.py | 6 ++- autobot-backend/api/agent_config.py | 4 +- autobot-backend/api/analytics_controller.py | 4 +- .../codebase_analytics/endpoints/sources.py | 8 +++- autobot-backend/api/intelligent_agent.py | 4 +- .../api/long_running_operations.py | 12 +++-- autobot-backend/api/terminal_websocket.py | 4 +- .../graph_inject_warning_test.py | 16 +++++-- autobot-backend/chat_workflow/tool_handler.py | 6 ++- .../auto-tools/logging_standardizer.py | 5 ++- .../auto-tools/performance_optimizer.py | 5 ++- .../auto-tools/playwright_sanitizer.py | 6 ++- .../auto-tools/security_deep_sanitizer.py | 6 ++- .../auto-tools/security_sanitizer.py | 6 ++- .../pattern_analysis/analyzer.py | 12 ++++- autobot-backend/conversation.py | 4 +- autobot-backend/dependency_container.py | 5 ++- autobot-backend/diagnostics.py | 12 ++++- autobot-backend/elevation_wrapper.py | 12 ++++- autobot-backend/initialization/lifespan.py | 11 ++--- autobot-backend/judges/__init__.py | 4 +- autobot-backend/knowledge/facts.py | 8 +++- autobot-backend/knowledge/metadata.py | 24 ++++++++-- autobot-backend/knowledge/search.py | 14 +++++- autobot-backend/knowledge/stats.py | 6 ++- autobot-backend/knowledge/suggestions.py | 18 ++++++-- autobot-backend/knowledge/versioning.py | 6 ++- autobot-backend/knowledge_factory.py | 3 +- .../adapters/layer_inference_adapter.py | 5 ++- .../llm_interface_pkg/interface.py | 8 +--- .../optimization/hf_quantizer.py | 4 +- .../optimization/model_inspector.py | 16 ++++--- .../optimization/model_inspector_test.py | 35 +++++++++++---- .../optimization/pipeline.py | 10 ++++- autobot-backend/llm_multi_provider.py | 4 +- .../llm_providers/custom_openai_provider.py | 8 +--- .../llm_providers/huggingface_provider.py | 1 + .../llm_providers/ollama_provider.py | 6 +-- .../llm_providers/openai_provider.py | 1 + .../llm_providers/provider_registry.py | 10 +++-- autobot-backend/npu_integration.py | 6 ++- autobot-backend/npu_semantic_search.py | 11 ++++- .../orchestration/execution_modes_test.py | 4 +- .../orchestration/workflow_executor.py | 26 +++++------ autobot-backend/research_browser_manager.py | 4 +- .../security/domain_security_test.py | 8 +++- .../security/threat_intelligence.py | 24 ++++++++-- .../services/access_control_metrics.py | 10 ++++- .../services/agent_terminal/service.py | 6 ++- .../services/autoresearch/archive.py | 4 +- .../services/autoresearch/config.py | 8 +--- .../autoresearch/knowledge_synthesizer.py | 4 +- .../knowledge_synthesizer_test.py | 34 ++++++++------ .../services/autoresearch/prompt_optimizer.py | 26 +++++------ .../autoresearch/prompt_optimizer_test.py | 22 +++++++--- .../services/autoresearch/routes.py | 14 +++--- .../services/autoresearch/run_experiment.py | 2 +- .../services/autoresearch/runner.py | 4 +- .../services/autoresearch/runner_test.py | 5 +-- .../services/autoresearch/scorers.py | 22 ++++++---- .../services/autoresearch/store.py | 4 +- .../services/captcha_human_loop.py | 4 +- .../services/conversation_export.py | 8 +--- .../services/fact_extraction_service.py | 4 +- autobot-backend/services/feature_flags.py | 5 ++- .../services/knowledge/doc_indexer.py | 4 +- autobot-backend/services/llm_cost_tracker.py | 5 ++- autobot-backend/services/llm_service.py | 12 +++-- .../services/playwright_service.py | 14 +++++- .../services/redis_service_manager.py | 24 +++++++--- autobot-backend/services/semantic_analyzer.py | 4 +- .../services/temporal_invalidation_service.py | 24 +++++++--- .../services/terminal_secrets_service.py | 1 - .../services/user_behavior_analytics.py | 6 ++- .../services/workflow_automation/executor.py | 44 +++++++++++++------ .../services/workflow_automation/models.py | 25 ++++++++--- .../workflow_automation/persistence.py | 4 +- autobot-backend/startup_validator.py | 15 +++++-- autobot-backend/takeover_manager.e2e_test.py | 6 ++- autobot-backend/takeover_manager.py | 5 ++- .../test_cache_response_json_response.py | 1 - autobot-backend/tools/terminal_tool.py | 6 ++- .../utils/gpu_acceleration_optimizer.py | 4 +- autobot-slm-backend/api/updates.py | 8 +++- .../monitoring/performance_dashboard.py | 4 +- 89 files changed, 590 insertions(+), 255 deletions(-) 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-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.""" From 90476e9106c2ac3654c47f12f516560b29ed280c Mon Sep 17 00:00:00 2001 From: mrveiss Date: Fri, 3 Apr 2026 23:32:28 +0300 Subject: [PATCH 2/2] fix(knowledge-graph): resize Three.js renderer when container dimensions change (#3370) Add a ResizeObserver in initGraph() that calls graph.value.width(w).height(h) whenever the container's contentRect changes (entity details panel, window resize, sidebar collapse). Disconnect it at the top of disposeGraph() to prevent stale callbacks after teardown. Co-Authored-By: Claude Sonnet 4.6 --- .../components/knowledge/KnowledgeGraph3D.vue | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) 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()