From 1feeadf8d2e5a7ba8153c8da4957d4101fca4c44 Mon Sep 17 00:00:00 2001 From: aitbc1 Date: Fri, 13 Mar 2026 11:34:30 +0000 Subject: [PATCH] fix: make CLI robust to missing coordinator dependencies - Replace hardcoded absolute paths with project-relative resolution - Add AITBC_SERVICES_PATH environment variable override - Wrap service imports in try/except with graceful degradation - Add aiohttp to CLI requirements - Create missing README.md for aitbc-agent-sdk to fix poetry build - Make run_all_tests.sh portable with PROJECT_ROOT calculation - Fix enterprise_integration.py path handling CLI now loads successfully even when coordinator-api services are not installed. Advanced commands fail with helpful hints instead of crashing the entire CLI. --- cli/aitbc_cli/commands/advanced_analytics.py | 50 +++++++++++++++--- cli/aitbc_cli/commands/ai_surveillance.py | 52 ++++++++++++++++--- cli/aitbc_cli/commands/ai_trading.py | 45 +++++++++++++--- .../commands/enterprise_integration.py | 42 +++++++++++---- cli/aitbc_cli/commands/regulatory.py | 48 ++++++++++++++--- cli/aitbc_cli/commands/surveillance.py | 48 ++++++++++++++--- cli/requirements.txt | 1 + packages/py/aitbc-agent-sdk/README.md | 18 +++++++ run_all_tests.sh | 31 ++++++----- 9 files changed, 280 insertions(+), 55 deletions(-) create mode 100644 packages/py/aitbc-agent-sdk/README.md diff --git a/cli/aitbc_cli/commands/advanced_analytics.py b/cli/aitbc_cli/commands/advanced_analytics.py index 16cf09d1..fd330992 100755 --- a/cli/aitbc_cli/commands/advanced_analytics.py +++ b/cli/aitbc_cli/commands/advanced_analytics.py @@ -10,14 +10,50 @@ import json from typing import Optional, List, Dict, Any from datetime import datetime, timedelta -# Import advanced analytics +# Import advanced analytics with robust path resolution +import os import sys -sys.path.append('/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services') -from advanced_analytics import ( - start_analytics_monitoring, stop_analytics_monitoring, get_dashboard_data, - create_analytics_alert, get_analytics_summary, advanced_analytics, - MetricType, Timeframe -) + +_services_path = os.environ.get('AITBC_SERVICES_PATH') +if _services_path: + if os.path.isdir(_services_path): + if _services_path not in sys.path: + sys.path.insert(0, _services_path) + else: + print(f"Warning: AITBC_SERVICES_PATH set but not a directory: {_services_path}", file=sys.stderr) +else: + _project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + _computed_services = os.path.join(_project_root, 'apps', 'coordinator-api', 'src', 'app', 'services') + if os.path.isdir(_computed_services) and _computed_services not in sys.path: + sys.path.insert(0, _computed_services) + else: + _fallback = '/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services' + if os.path.isdir(_fallback) and _fallback not in sys.path: + sys.path.insert(0, _fallback) + +try: + from advanced_analytics import ( + start_analytics_monitoring, stop_analytics_monitoring, get_dashboard_data, + create_analytics_alert, get_analytics_summary, advanced_analytics, + MetricType, Timeframe + ) + _import_error = None +except ImportError as e: + _import_error = e + + def _missing(*args, **kwargs): + raise ImportError( + f"Required service module 'advanced_analytics' could not be imported: {_import_error}. " + "Ensure coordinator-api dependencies are installed or set AITBC_SERVICES_PATH." + ) + start_analytics_monitoring = stop_analytics_monitoring = get_dashboard_data = _missing + create_analytics_alert = get_analytics_summary = _missing + advanced_analytics = None + + class MetricType: + pass + class Timeframe: + pass @click.group() def advanced_analytics_group(): diff --git a/cli/aitbc_cli/commands/ai_surveillance.py b/cli/aitbc_cli/commands/ai_surveillance.py index 9da5865b..0ddca999 100755 --- a/cli/aitbc_cli/commands/ai_surveillance.py +++ b/cli/aitbc_cli/commands/ai_surveillance.py @@ -10,14 +10,52 @@ import json from typing import Optional, List, Dict, Any from datetime import datetime -# Import AI surveillance system +# Import AI surveillance system with robust path resolution +import os import sys -sys.path.append('/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services') -from ai_surveillance import ( - start_ai_surveillance, stop_ai_surveillance, get_surveillance_summary, - get_user_risk_profile, list_active_alerts, analyze_behavior_patterns, - ai_surveillance, SurveillanceType, RiskLevel, AlertPriority -) + +_services_path = os.environ.get('AITBC_SERVICES_PATH') +if _services_path: + if os.path.isdir(_services_path): + if _services_path not in sys.path: + sys.path.insert(0, _services_path) + else: + print(f"Warning: AITBC_SERVICES_PATH set but not a directory: {_services_path}", file=sys.stderr) +else: + _project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + _computed_services = os.path.join(_project_root, 'apps', 'coordinator-api', 'src', 'app', 'services') + if os.path.isdir(_computed_services) and _computed_services not in sys.path: + sys.path.insert(0, _computed_services) + else: + _fallback = '/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services' + if os.path.isdir(_fallback) and _fallback not in sys.path: + sys.path.insert(0, _fallback) + +try: + from ai_surveillance import ( + start_ai_surveillance, stop_ai_surveillance, get_surveillance_summary, + get_user_risk_profile, list_active_alerts, analyze_behavior_patterns, + ai_surveillance, SurveillanceType, RiskLevel, AlertPriority + ) + _import_error = None +except ImportError as e: + _import_error = e + + def _missing(*args, **kwargs): + raise ImportError( + f"Required service module 'ai_surveillance' could not be imported: {_import_error}. " + "Ensure coordinator-api dependencies are installed or set AITBC_SERVICES_PATH." + ) + start_ai_surveillance = stop_ai_surveillance = get_surveillance_summary = _missing + get_user_risk_profile = list_active_alerts = analyze_behavior_patterns = _missing + ai_surveillance = None + + class SurveillanceType: + pass + class RiskLevel: + pass + class AlertPriority: + pass @click.group() def ai_surveillance_group(): diff --git a/cli/aitbc_cli/commands/ai_trading.py b/cli/aitbc_cli/commands/ai_trading.py index dea988a3..a145ad8d 100755 --- a/cli/aitbc_cli/commands/ai_trading.py +++ b/cli/aitbc_cli/commands/ai_trading.py @@ -10,13 +10,46 @@ import json from typing import Optional, List, Dict, Any from datetime import datetime, timedelta -# Import AI trading engine +# Import AI trading engine with robust path resolution +import os import sys -sys.path.append('/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services') -from ai_trading_engine import ( - initialize_ai_engine, train_strategies, generate_trading_signals, - get_engine_status, ai_trading_engine, TradingStrategy -) + +_services_path = os.environ.get('AITBC_SERVICES_PATH') +if _services_path: + if os.path.isdir(_services_path): + if _services_path not in sys.path: + sys.path.insert(0, _services_path) + else: + print(f"Warning: AITBC_SERVICES_PATH set but not a directory: {_services_path}", file=sys.stderr) +else: + _project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + _computed_services = os.path.join(_project_root, 'apps', 'coordinator-api', 'src', 'app', 'services') + if os.path.isdir(_computed_services) and _computed_services not in sys.path: + sys.path.insert(0, _computed_services) + else: + _fallback = '/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services' + if os.path.isdir(_fallback) and _fallback not in sys.path: + sys.path.insert(0, _fallback) + +try: + from ai_trading_engine import ( + initialize_ai_engine, train_strategies, generate_trading_signals, + get_engine_status, ai_trading_engine, TradingStrategy + ) + _import_error = None +except ImportError as e: + _import_error = e + + def _missing(*args, **kwargs): + raise ImportError( + f"Required service module 'ai_trading_engine' could not be imported: {_import_error}. " + "Ensure coordinator-api dependencies are installed or set AITBC_SERVICES_PATH." + ) + initialize_ai_engine = train_strategies = generate_trading_signals = get_engine_status = _missing + ai_trading_engine = None + + class TradingStrategy: + pass @click.group() def ai_trading(): diff --git a/cli/aitbc_cli/commands/enterprise_integration.py b/cli/aitbc_cli/commands/enterprise_integration.py index f8d0fd74..79a56c0b 100755 --- a/cli/aitbc_cli/commands/enterprise_integration.py +++ b/cli/aitbc_cli/commands/enterprise_integration.py @@ -12,18 +12,40 @@ from datetime import datetime # Import enterprise integration services using importlib to avoid naming conflicts import importlib.util +import os -spec = importlib.util.spec_from_file_location("enterprise_integration_service", "/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services/enterprise_integration.py") -ei = importlib.util.module_from_spec(spec) -spec.loader.exec_module(ei) +_services_path = os.environ.get('AITBC_SERVICES_PATH') +if _services_path: + base_dir = _services_path +else: + _project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + base_dir = os.path.join(_project_root, 'apps', 'coordinator-api', 'src', 'app', 'services') + if not os.path.isdir(base_dir): + base_dir = '/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services' -create_tenant = ei.create_tenant -get_tenant_info = ei.get_tenant_info -generate_api_key = ei.generate_api_key -register_integration = ei.register_integration -get_system_status = ei.get_system_status -list_tenants = ei.list_tenants -list_integrations = ei.list_integrations +module_path = os.path.join(base_dir, 'enterprise_integration.py') +if os.path.isfile(module_path): + spec = importlib.util.spec_from_file_location("enterprise_integration_service", module_path) + ei = importlib.util.module_from_spec(spec) + spec.loader.exec_module(ei) + create_tenant = ei.create_tenant + get_tenant_info = ei.get_tenant_info + generate_api_key = ei.generate_api_key + register_integration = ei.register_integration + get_system_status = ei.get_system_status + list_tenants = ei.list_tenants + list_integrations = ei.list_integrations + EnterpriseAPIGateway = getattr(ei, 'EnterpriseAPIGateway', None) +else: + # Provide stubs if module not found + def _missing(*args, **kwargs): + raise ImportError( + f"Could not load enterprise_integration.py from {module_path}. " + "Ensure coordinator-api services are available or set AITBC_SERVICES_PATH." + ) + create_tenant = get_tenant_info = generate_api_key = _missing + register_integration = get_system_status = list_tenants = list_integrations = _missing + EnterpriseAPIGateway = None @click.group() def enterprise_integration_group(): diff --git a/cli/aitbc_cli/commands/regulatory.py b/cli/aitbc_cli/commands/regulatory.py index 34261dd3..0f19de58 100755 --- a/cli/aitbc_cli/commands/regulatory.py +++ b/cli/aitbc_cli/commands/regulatory.py @@ -10,13 +10,49 @@ import json from typing import Optional, List, Dict, Any from datetime import datetime, timedelta -# Import regulatory reporting system +# Import regulatory reporting system with robust path resolution +import os import sys -sys.path.append('/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services') -from regulatory_reporting import ( - generate_sar, generate_compliance_summary, list_reports, - regulatory_reporter, ReportType, ReportStatus, RegulatoryBody -) + +_services_path = os.environ.get('AITBC_SERVICES_PATH') +if _services_path: + if os.path.isdir(_services_path): + if _services_path not in sys.path: + sys.path.insert(0, _services_path) + else: + print(f"Warning: AITBC_SERVICES_PATH set but not a directory: {_services_path}", file=sys.stderr) +else: + _project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + _computed_services = os.path.join(_project_root, 'apps', 'coordinator-api', 'src', 'app', 'services') + if os.path.isdir(_computed_services) and _computed_services not in sys.path: + sys.path.insert(0, _computed_services) + else: + _fallback = '/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services' + if os.path.isdir(_fallback) and _fallback not in sys.path: + sys.path.insert(0, _fallback) + +try: + from regulatory_reporting import ( + generate_sar, generate_compliance_summary, list_reports, + regulatory_reporter, ReportType, ReportStatus, RegulatoryBody + ) + _import_error = None +except ImportError as e: + _import_error = e + + def _missing(*args, **kwargs): + raise ImportError( + f"Required service module 'regulatory_reporting' could not be imported: {_import_error}. " + "Ensure coordinator-api dependencies are installed or set AITBC_SERVICES_PATH." + ) + generate_sar = generate_compliance_summary = list_reports = regulatory_reporter = _missing + + class ReportType: + pass + class ReportStatus: + pass + class RegulatoryBody: + pass @click.group() def regulatory(): diff --git a/cli/aitbc_cli/commands/surveillance.py b/cli/aitbc_cli/commands/surveillance.py index b4fb7e70..aff43994 100755 --- a/cli/aitbc_cli/commands/surveillance.py +++ b/cli/aitbc_cli/commands/surveillance.py @@ -10,13 +10,49 @@ import json from typing import Optional, List, Dict, Any from datetime import datetime, timedelta -# Import surveillance system +# Import surveillance system with robust path resolution +import os import sys -sys.path.append('/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services') -from trading_surveillance import ( - start_surveillance, stop_surveillance, get_alerts, - get_surveillance_summary, AlertLevel -) + +# Determine services path: use AITBC_SERVICES_PATH if set, else compute relative to repo layout +_services_path = os.environ.get('AITBC_SERVICES_PATH') +if _services_path: + if os.path.isdir(_services_path): + if _services_path not in sys.path: + sys.path.insert(0, _services_path) + else: + print(f"Warning: AITBC_SERVICES_PATH set but not a directory: {_services_path}", file=sys.stderr) +else: + # Compute project root relative to this file: cli/aitbc_cli/commands -> 3 levels up to project root + _project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + _computed_services = os.path.join(_project_root, 'apps', 'coordinator-api', 'src', 'app', 'services') + if os.path.isdir(_computed_services) and _computed_services not in sys.path: + sys.path.insert(0, _computed_services) + else: + # Fallback to known hardcoded path if it exists (for legacy deployments) + _fallback = '/home/oib/windsurf/aitbc/apps/coordinator-api/src/app/services' + if os.path.isdir(_fallback) and _fallback not in sys.path: + sys.path.insert(0, _fallback) + +try: + from trading_surveillance import ( + start_surveillance, stop_surveillance, get_alerts, + get_surveillance_summary, AlertLevel + ) + _import_error = None +except ImportError as e: + _import_error = e + + def _missing(*args, **kwargs): + raise ImportError( + f"Required service module 'trading_surveillance' could not be imported: {_import_error}. " + "Ensure coordinator-api dependencies are installed or set AITBC_SERVICES_PATH." + ) + start_surveillance = stop_surveillance = get_alerts = get_surveillance_summary = _missing + + class AlertLevel: + """Stub for AlertLevel when import fails.""" + pass @click.group() def surveillance(): diff --git a/cli/requirements.txt b/cli/requirements.txt index 340d0975..b53febc8 100644 --- a/cli/requirements.txt +++ b/cli/requirements.txt @@ -9,3 +9,4 @@ click-completion>=0.5.2 tabulate>=0.9.0 colorama>=0.4.4 python-dotenv>=0.19.0 +aiohttp>=3.9.0 diff --git a/packages/py/aitbc-agent-sdk/README.md b/packages/py/aitbc-agent-sdk/README.md new file mode 100644 index 00000000..99fc7678 --- /dev/null +++ b/packages/py/aitbc-agent-sdk/README.md @@ -0,0 +1,18 @@ +# aitbc-agent-sdk + +Agent SDK for AITBC (AI Agent Compute Network). + +This package provides tools and abstractions for building AI agents that participate in the AITBC decentralized compute marketplace. + +## Installation + +```bash +pip install -e .[dev] +``` + +## Development + +Run tests: +```bash +pytest +``` diff --git a/run_all_tests.sh b/run_all_tests.sh index e6259cf2..f31452e4 100755 --- a/run_all_tests.sh +++ b/run_all_tests.sh @@ -6,6 +6,10 @@ echo "==========================================" echo "Testing localhost, aitbc, and aitbc1 with all CLI features" echo "" +# Resolve project root (directory containing this script) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR" && pwd)" + # Function to run a test scenario run_scenario() { local scenario_name=$1 @@ -90,14 +94,15 @@ check_prerequisites() { echo "" echo "📋 Checking user configurations..." - # Check miner1 and client1 configurations - if [ -f "/home/oib/windsurf/aitbc/home/miner1/miner_wallet.json" ]; then + # Check miner1 and client1 configurations (relative to project root) + local home_dir="$PROJECT_ROOT/home" + if [ -f "$home_dir/miner1/miner_wallet.json" ]; then echo "✅ miner1 configuration found" else echo "❌ miner1 configuration missing" fi - if [ -f "/home/oib/windsurf/aitbc/home/client1/client_wallet.json" ]; then + if [ -f "$home_dir/client1/client_wallet.json" ]; then echo "✅ client1 configuration found" else echo "❌ client1 configuration missing" @@ -196,10 +201,10 @@ main() { # Run scenario tests local scenarios=( - "Scenario A: Localhost GPU Miner → aitbc Marketplace:/home/oib/windsurf/aitbc/test_scenario_a.sh" - "Scenario B: Localhost GPU Client → aitbc1 Marketplace:/home/oib/windsurf/aitbc/test_scenario_b.sh" - "Scenario C: aitbc Container User Operations:/home/oib/windsurf/aitbc/test_scenario_c.sh" - "Scenario D: aitbc1 Container User Operations:/home/oib/windsurf/aitbc/test_scenario_d.sh" + "Scenario A: Localhost GPU Miner → aitbc Marketplace:$PROJECT_ROOT/test_scenario_a.sh" + "Scenario B: Localhost GPU Client → aitbc1 Marketplace:$PROJECT_ROOT/test_scenario_b.sh" + "Scenario C: aitbc Container User Operations:$PROJECT_ROOT/test_scenario_c.sh" + "Scenario D: aitbc1 Container User Operations:$PROJECT_ROOT/test_scenario_d.sh" ) for scenario_info in "${scenarios[@]}"; do @@ -215,7 +220,7 @@ main() { echo "" echo "🔧 Running Comprehensive Test Suite" echo "==================================" - if python3 /home/oib/windsurf/aitbc/test_multi_site.py; then + if python3 "$PROJECT_ROOT/test_multi_site.py"; then echo "✅ Comprehensive test suite passed" passed_count=$((passed_count + 1)) else @@ -236,19 +241,19 @@ case "${1:-all}" in run_cli_tests ;; "scenario-a") - run_scenario "Scenario A" "/home/oib/windsurf/aitbc/test_scenario_a.sh" + run_scenario "Scenario A" "$PROJECT_ROOT/test_scenario_a.sh" ;; "scenario-b") - run_scenario "Scenario B" "/home/oib/windsurf/aitbc/test_scenario_b.sh" + run_scenario "Scenario B" "$PROJECT_ROOT/test_scenario_b.sh" ;; "scenario-c") - run_scenario "Scenario C" "/home/oib/windsurf/aitbc/test_scenario_c.sh" + run_scenario "Scenario C" "$PROJECT_ROOT/test_scenario_c.sh" ;; "scenario-d") - run_scenario "Scenario D" "/home/oib/windsurf/aitbc/test_scenario_d.sh" + run_scenario "Scenario D" "$PROJECT_ROOT/test_scenario_d.sh" ;; "comprehensive") - python3 /home/oib/windsurf/aitbc/test_multi_site.py + python3 "$PROJECT_ROOT/test_multi_site.py" ;; "all"|*) main