diff --git a/infra/scripts/post-provision/seed_knowledge_bases.py b/infra/scripts/post-provision/seed_knowledge_bases.py index 5505196a0..4f6bf0205 100644 --- a/infra/scripts/post-provision/seed_knowledge_bases.py +++ b/infra/scripts/post-provision/seed_knowledge_bases.py @@ -21,7 +21,6 @@ - The caller needs "Search Service Contributor" role on the search service. """ -import json import os import sys from pathlib import Path @@ -37,9 +36,12 @@ SEARCH_ENDPOINT = os.environ.get("AZURE_AI_SEARCH_ENDPOINT", "").rstrip("/") AI_SERVICES_ENDPOINT = os.environ.get("AZURE_OPENAI_ENDPOINT", "").rstrip("/") -if not SEARCH_ENDPOINT: - print("ERROR: AZURE_AI_SEARCH_ENDPOINT must be set.") - sys.exit(1) + +def _validate_required_env() -> None: + """Validate required environment variables; exit(1) if missing.""" + if not SEARCH_ENDPOINT: + print("ERROR: AZURE_AI_SEARCH_ENDPOINT must be set.") + sys.exit(1) _SEARCH_SCOPE = "https://search.azure.com/.default" @@ -384,6 +386,7 @@ def _parse_only_filter() -> set[str] | None: def main() -> None: """Provision all knowledge bases.""" + _validate_required_env() print(f"Search endpoint: {SEARCH_ENDPOINT}") print(f"AI services endpoint: {AI_SERVICES_ENDPOINT or '(not set — KB will have no model)'}") diff --git a/src/backend/api/router.py b/src/backend/api/router.py index f683e2dab..2297e9571 100644 --- a/src/backend/api/router.py +++ b/src/backend/api/router.py @@ -127,8 +127,13 @@ async def _heartbeat() -> None: heartbeat_task.cancel() try: await heartbeat_task - except (asyncio.CancelledError, Exception): + except asyncio.CancelledError: + # Expected: we just cancelled the heartbeat task above. pass + except Exception as e: + logging.debug( + f"Unexpected error awaiting cancelled heartbeat task for user {user_id}: {e}" + ) await connection_config.close_connection(process_id=process_id) @@ -428,7 +433,9 @@ async def run_orchestration_task(): # Give the cancelled task a chance to clean up await asyncio.sleep(0) except Exception: - pass + logger.exception( + "Failed to cancel prior orchestration task for user '%s'", user_id + ) orchestration_config.active_tasks.pop(user_id, None) # Schedule new task and register it so subsequent requests can cancel it diff --git a/src/backend/orchestration/orchestration_manager.py b/src/backend/orchestration/orchestration_manager.py index cb417465d..77846e39f 100644 --- a/src/backend/orchestration/orchestration_manager.py +++ b/src/backend/orchestration/orchestration_manager.py @@ -736,8 +736,12 @@ def _get_team_agent_names(workflow) -> list[str]: ] if names: return names - except Exception: - pass + except Exception as exc: + OrchestrationManager.logger.debug( + "Failed to read executor names from workflow; falling back to team config: %s", + exc, + exc_info=True, + ) team_config = getattr(workflow, "_team_config", None) return [ @@ -914,7 +918,6 @@ async def _handle_tool_approvals( Returns: A ``{request_id: approval_response}`` dict. """ - import json import threading from tools.clarification_tool import store_answer diff --git a/src/backend/orchestration/plan_review_helpers.py b/src/backend/orchestration/plan_review_helpers.py index 72dd820b8..efb2d536e 100644 --- a/src/backend/orchestration/plan_review_helpers.py +++ b/src/backend/orchestration/plan_review_helpers.py @@ -95,7 +95,6 @@ def get_magentic_prompt_kwargs( "is INVALID — regenerate it\nuntil every listed agent appears as a step.\n" ) - scope_policy = """ TEAM SCOPE POLICY (CRITICAL — EVALUATE THIS FIRST, BEFORE ANY OTHER RULE): diff --git a/src/tests/agents/test_agent_template_integration.py b/src/tests/agents/test_agent_template_integration.py index 15a22b883..4e4f1d0b0 100644 --- a/src/tests/agents/test_agent_template_integration.py +++ b/src/tests/agents/test_agent_template_integration.py @@ -27,7 +27,6 @@ from pathlib import Path import pytest -import pytest_asyncio # --------------------------------------------------------------------------- # Make sure 'src/backend' is on the path (covers running from repo root and diff --git a/src/tests/backend/agents/test_agent_factory.py b/src/tests/backend/agents/test_agent_factory.py index 2444408e1..77f03d62b 100644 --- a/src/tests/backend/agents/test_agent_factory.py +++ b/src/tests/backend/agents/test_agent_factory.py @@ -13,7 +13,7 @@ import logging import sys from types import SimpleNamespace -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import AsyncMock, Mock import pytest diff --git a/src/tests/backend/common/database/test_database_base.py b/src/tests/backend/common/database/test_database_base.py index 72bce96b0..e0b7b75b8 100644 --- a/src/tests/backend/common/database/test_database_base.py +++ b/src/tests/backend/common/database/test_database_base.py @@ -3,7 +3,7 @@ import os import sys from typing import Any, Dict, List, Optional, Type -from unittest.mock import AsyncMock, Mock, patch +from unittest.mock import Mock import pytest diff --git a/src/tests/backend/common/utils/test_agent_utils.py b/src/tests/backend/common/utils/test_agent_utils.py index 91d378eeb..d8e8978d4 100644 --- a/src/tests/backend/common/utils/test_agent_utils.py +++ b/src/tests/backend/common/utils/test_agent_utils.py @@ -28,10 +28,8 @@ sys.modules['common.models'] = Mock() sys.modules['common.models.messages'] = Mock() -import pytest - from backend.common.database.database_base import DatabaseBase -from backend.common.models.messages import (CurrentTeamAgent, DataType, +from backend.common.models.messages import (CurrentTeamAgent, TeamConfiguration) from backend.common.utils.agent_utils import (generate_assistant_id, get_database_team_agent_id) diff --git a/src/tests/backend/common/utils/test_event_utils.py b/src/tests/backend/common/utils/test_event_utils.py index 3696e79f5..cc3517caa 100644 --- a/src/tests/backend/common/utils/test_event_utils.py +++ b/src/tests/backend/common/utils/test_event_utils.py @@ -4,7 +4,7 @@ import os import sys from pathlib import Path -from unittest.mock import MagicMock, Mock, patch +from unittest.mock import Mock, patch import pytest diff --git a/src/tests/backend/middleware/test_health_check.py b/src/tests/backend/middleware/test_health_check.py index 5841a1cb0..e5d2bd36c 100644 --- a/src/tests/backend/middleware/test_health_check.py +++ b/src/tests/backend/middleware/test_health_check.py @@ -1,7 +1,5 @@ """Unit tests for backend.middleware.health_check module.""" -import asyncio -import logging -from unittest.mock import AsyncMock, MagicMock, Mock, patch +from unittest.mock import AsyncMock, Mock, patch import pytest diff --git a/src/tests/backend/models/test_messages.py b/src/tests/backend/models/test_messages.py index 725069b70..282789f70 100644 --- a/src/tests/backend/models/test_messages.py +++ b/src/tests/backend/models/test_messages.py @@ -5,8 +5,6 @@ import os import sys -import pytest - # backend/models/messages.py has internal imports from common.models.messages # and models.plan_models using paths relative to src/backend/. Add src/backend/ # to sys.path so those internal imports resolve when we load backend.models.messages. @@ -24,7 +22,7 @@ ReplanApprovalResponse, UserClarificationRequest, UserClarificationResponse) -from backend.models.plan_models import MPlan, MStep, PlanStatus +from backend.models.plan_models import MPlan, PlanStatus class TestAgentMessage: diff --git a/src/tests/backend/orchestration/test_orchestration_manager.py b/src/tests/backend/orchestration/test_orchestration_manager.py index 15245883e..dd8fe5225 100644 --- a/src/tests/backend/orchestration/test_orchestration_manager.py +++ b/src/tests/backend/orchestration/test_orchestration_manager.py @@ -7,11 +7,10 @@ - _process_event_stream() — event dispatch """ -import asyncio import logging import os import sys -from unittest.mock import AsyncMock, MagicMock, Mock, patch +from unittest.mock import AsyncMock, Mock, patch import pytest diff --git a/src/tests/backend/services/test_mcp_service.py b/src/tests/backend/services/test_mcp_service.py index 666b92240..44030fb17 100644 --- a/src/tests/backend/services/test_mcp_service.py +++ b/src/tests/backend/services/test_mcp_service.py @@ -3,7 +3,7 @@ import os import sys -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import MagicMock, patch import pytest from aiohttp import ClientError diff --git a/src/tests/backend/test_app.py b/src/tests/backend/test_app.py index 8784d276e..c16e83d6b 100644 --- a/src/tests/backend/test_app.py +++ b/src/tests/backend/test_app.py @@ -13,7 +13,7 @@ import pytest import sys import os -from unittest.mock import Mock, AsyncMock, MagicMock, patch, NonCallableMock +from unittest.mock import Mock, AsyncMock, MagicMock, patch # Environment variables are set by conftest.py, but ensure they're available os.environ.setdefault("APPLICATIONINSIGHTS_CONNECTION_STRING", "InstrumentationKey=test-key-12345") @@ -47,7 +47,6 @@ del sys.modules[_ma_key] # Mock external dependencies that may not be installed in test environment -from fastapi import APIRouter # Mock azure.monitor.opentelemetry module mock_azure_monitor_module = ModuleType('configure_azure_monitor') diff --git a/test_mcp_tools.py b/test_mcp_tools.py index 39fcaf94e..758bdd7f1 100644 --- a/test_mcp_tools.py +++ b/test_mcp_tools.py @@ -1,5 +1,6 @@ """Quick test to list MCP tools on /hr/mcp.""" import json +import sys import httpx @@ -31,7 +32,7 @@ if not sid: print("No session ID, aborting") - exit(1) + sys.exit(1) # 2. List tools HEADERS["mcp-session-id"] = sid