From 90b525254baa2fa696b48bc72ad1be7a5fa674c5 Mon Sep 17 00:00:00 2001 From: aitbc Date: Mon, 27 Apr 2026 10:28:25 +0200 Subject: [PATCH] aitbc: implement lazy loading for module imports to improve startup performance --- aitbc/__init__.py | 586 ++----- apps/agent-coordinator/src/app/exceptions.py | 31 + apps/agent-coordinator/src/app/lifespan.py | 40 + apps/agent-coordinator/src/app/main.py | 1494 +---------------- apps/agent-coordinator/src/app/middleware.py | 27 + apps/agent-coordinator/src/app/models.py | 30 + .../src/app/routers/__init__.py | 14 + .../src/app/routers/agents.py | 142 ++ apps/agent-coordinator/src/app/routers/ai.py | 135 ++ .../src/app/routers/alerts.py | 218 +++ .../agent-coordinator/src/app/routers/auth.py | 196 +++ .../src/app/routers/consensus.py | 133 ++ .../src/app/routers/health.py | 57 + .../src/app/routers/messages.py | 185 ++ .../src/app/routers/monitoring.py | 129 ++ .../src/app/routers/tasks.py | 80 + .../src/app/routers/users.py | 244 +++ apps/agent-coordinator/src/app/state.py | 15 + cli/parser_context.py | 28 + cli/parsers/__init__.py | 19 + cli/parsers/agent.py | 51 + cli/parsers/ai.py | 77 + cli/parsers/blockchain.py | 83 + cli/parsers/bridge.py | 31 + cli/parsers/genesis.py | 29 + cli/parsers/market.py | 97 ++ cli/parsers/messaging.py | 84 + cli/parsers/network.py | 41 + cli/parsers/openclaw.py | 29 + cli/parsers/pool_hub.py | 44 + cli/parsers/resource.py | 36 + cli/parsers/system.py | 178 ++ cli/parsers/wallet.py | 102 ++ cli/parsers/workflow.py | 34 + cli/unified_cli.py | 969 ++--------- 35 files changed, 2975 insertions(+), 2713 deletions(-) create mode 100644 apps/agent-coordinator/src/app/exceptions.py create mode 100644 apps/agent-coordinator/src/app/lifespan.py create mode 100644 apps/agent-coordinator/src/app/middleware.py create mode 100644 apps/agent-coordinator/src/app/models.py create mode 100644 apps/agent-coordinator/src/app/routers/__init__.py create mode 100644 apps/agent-coordinator/src/app/routers/agents.py create mode 100644 apps/agent-coordinator/src/app/routers/ai.py create mode 100644 apps/agent-coordinator/src/app/routers/alerts.py create mode 100644 apps/agent-coordinator/src/app/routers/auth.py create mode 100644 apps/agent-coordinator/src/app/routers/consensus.py create mode 100644 apps/agent-coordinator/src/app/routers/health.py create mode 100644 apps/agent-coordinator/src/app/routers/messages.py create mode 100644 apps/agent-coordinator/src/app/routers/monitoring.py create mode 100644 apps/agent-coordinator/src/app/routers/tasks.py create mode 100644 apps/agent-coordinator/src/app/routers/users.py create mode 100644 apps/agent-coordinator/src/app/state.py create mode 100644 cli/parser_context.py create mode 100644 cli/parsers/__init__.py create mode 100644 cli/parsers/agent.py create mode 100644 cli/parsers/ai.py create mode 100644 cli/parsers/blockchain.py create mode 100644 cli/parsers/bridge.py create mode 100644 cli/parsers/genesis.py create mode 100644 cli/parsers/market.py create mode 100644 cli/parsers/messaging.py create mode 100644 cli/parsers/network.py create mode 100644 cli/parsers/openclaw.py create mode 100644 cli/parsers/pool_hub.py create mode 100644 cli/parsers/resource.py create mode 100644 cli/parsers/system.py create mode 100644 cli/parsers/wallet.py create mode 100644 cli/parsers/workflow.py diff --git a/aitbc/__init__.py b/aitbc/__init__.py index 55ed4cbc..3dfc487c 100644 --- a/aitbc/__init__.py +++ b/aitbc/__init__.py @@ -1,257 +1,199 @@ """ AITBC Package -Centralized utilities for AITBC applications +Centralized utilities for AITBC applications. """ +from __future__ import annotations + +from importlib import import_module +from typing import Any + from .aitbc_logging import get_logger, setup_logger from .constants import ( - DATA_DIR, - CONFIG_DIR, - LOG_DIR, - REPO_DIR, - KEYSTORE_DIR, - BLOCKCHAIN_DATA_DIR, - MARKETPLACE_DATA_DIR, - ENV_FILE, - NODE_ENV_FILE, - BLOCKCHAIN_RPC_PORT, - BLOCKCHAIN_P2P_PORT, AGENT_COORDINATOR_PORT, + BLOCKCHAIN_DATA_DIR, + BLOCKCHAIN_P2P_PORT, + BLOCKCHAIN_RPC_PORT, + CONFIG_DIR, + DATA_DIR, + ENV_FILE, + KEYSTORE_DIR, + LOG_DIR, + MARKETPLACE_DATA_DIR, MARKETPLACE_PORT, + NODE_ENV_FILE, PACKAGE_VERSION, + REPO_DIR, +) +from .env import ( + get_bool_env_var, + get_env_var, + get_float_env_var, + get_int_env_var, + get_list_env_var, + get_required_env_var, ) from .exceptions import ( AITBCError, - ConfigurationError, - NetworkError, AuthenticationError, - EncryptionError, - DatabaseError, - ValidationError, BridgeError, - RetryError, CircuitBreakerOpenError, + ConfigurationError, + DatabaseError, + EncryptionError, + NetworkError, RateLimitError, -) -from .env import ( - get_env_var, - get_required_env_var, - get_bool_env_var, - get_int_env_var, - get_float_env_var, - get_list_env_var, + RetryError, + ValidationError, ) from .paths import ( - get_data_path, - get_config_path, - get_log_path, - get_repo_path, ensure_dir, ensure_file_dir, - resolve_path, - get_keystore_path, get_blockchain_data_path, + get_config_path, + get_data_path, + get_keystore_path, + get_log_path, get_marketplace_data_path, -) -from .json_utils import ( - load_json, - save_json, - merge_json, - json_to_string, - string_to_json, - get_nested_value, - set_nested_value, - flatten_json, -) -from .http_client import AITBCHTTPClient, AsyncAITBCHTTPClient -from .config import BaseAITBCConfig, AITBCConfig -from .decorators import ( - retry, - timing, - cache_result, - validate_args, - handle_exceptions, - async_timing, -) -from .validation import ( - validate_address, - validate_hash, - validate_url, - validate_port, - validate_email, - validate_non_empty, - validate_positive_number, - validate_range, - validate_chain_id, - validate_uuid, -) -from .async_helpers import ( - run_sync, - gather_with_concurrency, - run_with_timeout, - batch_process, - sync_to_async, - async_to_sync, - retry_async, - wait_for_condition, -) -from .database import ( - DatabaseConnection, - get_database_connection, - ensure_database, - vacuum_database, - get_table_info, - table_exists, -) -from .monitoring import ( - MetricsCollector, - PerformanceTimer, - HealthChecker, -) -from .data_layer import DataLayer, MockDataGenerator, RealDataFetcher, get_data_layer -from .crypto import ( - derive_ethereum_address, - sign_transaction_hash, - verify_signature, - encrypt_private_key, - decrypt_private_key, - generate_secure_random_bytes, - keccak256_hash, - sha256_hash, - validate_ethereum_address, - generate_ethereum_private_key, -) -from .web3_utils import Web3Client, create_web3_client -from .security import ( - generate_token, - generate_api_key, - validate_token_format, - validate_api_key, - SessionManager, - APIKeyManager, - generate_secure_random_string, - generate_secure_random_int, - SecretManager, - hash_password, - verify_password, - generate_nonce, - generate_hmac, - verify_hmac, -) -from .time_utils import ( - get_utc_now, - get_timestamp_utc, - format_iso8601, - parse_iso8601, - timestamp_to_iso, - iso_to_timestamp, - format_duration, - format_duration_precise, - parse_duration, - add_duration, - subtract_duration, - get_time_until, - get_time_since, - calculate_deadline, - is_deadline_passed, - get_deadline_remaining, - format_time_ago, - format_time_in, - to_timezone, - get_timezone_offset, - is_business_hours, - get_start_of_day, - get_end_of_day, - get_start_of_week, - get_end_of_week, - get_start_of_month, - get_end_of_month, - sleep_until, - retry_until_deadline, - Timer, -) -from .api_utils import ( - APIResponse, - PaginatedResponse, - success_response, - error_response, - not_found_response, - unauthorized_response, - forbidden_response, - validation_error_response, - conflict_response, - internal_error_response, - PaginationParams, - paginate_items, - build_paginated_response, - RateLimitHeaders, - build_cors_headers, - build_standard_headers, - validate_sort_field, - validate_sort_order, - build_sort_params, - filter_fields, - exclude_fields, - sanitize_response, - merge_responses, - get_client_ip, - get_user_agent, - build_request_metadata, -) -from .events import ( - Event, - EventPriority, - EventBus, - AsyncEventBus, - event_handler, - publish_event, - get_global_event_bus, - set_global_event_bus, - EventFilter, - EventAggregator, - EventRouter, -) -from .queue_manager import ( - Job, - JobStatus, - JobPriority, - TaskQueue, - JobScheduler, - BackgroundTaskManager, - WorkerPool, - debounce, - throttle, -) -from .state import ( - StateTransition, - StateTransitionError, - StatePersistenceError, - StateMachine, - ConfigurableStateMachine, - StatePersistence, - AsyncStateMachine, - StateMonitor, - StateValidator, - StateSnapshot, -) -from .testing import ( - MockFactory, - TestDataGenerator, - TestHelpers, - MockResponse, - MockDatabase, - MockCache, - mock_async_call, - create_mock_config, - create_test_scenario, + get_repo_path, + resolve_path, ) __version__ = "0.6.0" + +_LAZY_EXPORTS: dict[str, tuple[str, str]] = { + "load_json": ("json_utils", "load_json"), + "save_json": ("json_utils", "save_json"), + "merge_json": ("json_utils", "merge_json"), + "json_to_string": ("json_utils", "json_to_string"), + "string_to_json": ("json_utils", "string_to_json"), + "get_nested_value": ("json_utils", "get_nested_value"), + "set_nested_value": ("json_utils", "set_nested_value"), + "flatten_json": ("json_utils", "flatten_json"), + "AITBCHTTPClient": ("http_client", "AITBCHTTPClient"), + "AsyncAITBCHTTPClient": ("http_client", "AsyncAITBCHTTPClient"), + "BaseAITBCConfig": ("config", "BaseAITBCConfig"), + "AITBCConfig": ("config", "AITBCConfig"), + "retry": ("decorators", "retry"), + "timing": ("decorators", "timing"), + "cache_result": ("decorators", "cache_result"), + "validate_args": ("decorators", "validate_args"), + "handle_exceptions": ("decorators", "handle_exceptions"), + "async_timing": ("decorators", "async_timing"), + "validate_address": ("validation", "validate_address"), + "validate_hash": ("validation", "validate_hash"), + "validate_url": ("validation", "validate_url"), + "validate_port": ("validation", "validate_port"), + "validate_email": ("validation", "validate_email"), + "validate_non_empty": ("validation", "validate_non_empty"), + "validate_positive_number": ("validation", "validate_positive_number"), + "validate_range": ("validation", "validate_range"), + "validate_chain_id": ("validation", "validate_chain_id"), + "validate_uuid": ("validation", "validate_uuid"), + "run_sync": ("async_helpers", "run_sync"), + "gather_with_concurrency": ("async_helpers", "gather_with_concurrency"), + "run_with_timeout": ("async_helpers", "run_with_timeout"), + "batch_process": ("async_helpers", "batch_process"), + "sync_to_async": ("async_helpers", "sync_to_async"), + "async_to_sync": ("async_helpers", "async_to_sync"), + "retry_async": ("async_helpers", "retry_async"), + "wait_for_condition": ("async_helpers", "wait_for_condition"), + "DatabaseConnection": ("database", "DatabaseConnection"), + "get_database_connection": ("database", "get_database_connection"), + "ensure_database": ("database", "ensure_database"), + "vacuum_database": ("database", "vacuum_database"), + "get_table_info": ("database", "get_table_info"), + "table_exists": ("database", "table_exists"), + "MetricsCollector": ("monitoring", "MetricsCollector"), + "PerformanceTimer": ("monitoring", "PerformanceTimer"), + "HealthChecker": ("monitoring", "HealthChecker"), + "DataLayer": ("data_layer", "DataLayer"), + "MockDataGenerator": ("data_layer", "MockDataGenerator"), + "RealDataFetcher": ("data_layer", "RealDataFetcher"), + "get_data_layer": ("data_layer", "get_data_layer"), + "derive_ethereum_address": ("crypto", "derive_ethereum_address"), + "sign_transaction_hash": ("crypto", "sign_transaction_hash"), + "verify_signature": ("crypto", "verify_signature"), + "encrypt_private_key": ("crypto", "encrypt_private_key"), + "decrypt_private_key": ("crypto", "decrypt_private_key"), + "generate_secure_random_bytes": ("crypto", "generate_secure_random_bytes"), + "keccak256_hash": ("crypto", "keccak256_hash"), + "sha256_hash": ("crypto", "sha256_hash"), + "validate_ethereum_address": ("crypto", "validate_ethereum_address"), + "generate_ethereum_private_key": ("crypto", "generate_ethereum_private_key"), + "Web3Client": ("web3_utils", "Web3Client"), + "create_web3_client": ("web3_utils", "create_web3_client"), + "generate_token": ("security", "generate_token"), + "generate_api_key": ("security", "generate_api_key"), + "validate_token_format": ("security", "validate_token_format"), + "validate_api_key": ("security", "validate_api_key"), + "SessionManager": ("security", "SessionManager"), + "APIKeyManager": ("security", "APIKeyManager"), + "generate_secure_random_string": ("security", "generate_secure_random_string"), + "generate_secure_random_int": ("security", "generate_secure_random_int"), + "SecretManager": ("security", "SecretManager"), + "hash_password": ("security", "hash_password"), + "verify_password": ("security", "verify_password"), + "generate_nonce": ("security", "generate_nonce"), + "generate_hmac": ("security", "generate_hmac"), + "verify_hmac": ("security", "verify_hmac"), +} + +for _name in ( + "get_utc_now get_timestamp_utc format_iso8601 parse_iso8601 timestamp_to_iso iso_to_timestamp " + "format_duration format_duration_precise parse_duration add_duration subtract_duration get_time_until " + "get_time_since calculate_deadline is_deadline_passed get_deadline_remaining format_time_ago " + "format_time_in to_timezone get_timezone_offset is_business_hours get_start_of_day get_end_of_day " + "get_start_of_week get_end_of_week get_start_of_month get_end_of_month sleep_until retry_until_deadline Timer" +).split(): + _LAZY_EXPORTS[_name] = ("time_utils", _name) + +for _name in ( + "APIResponse PaginatedResponse success_response error_response not_found_response unauthorized_response " + "forbidden_response validation_error_response conflict_response internal_error_response PaginationParams " + "paginate_items build_paginated_response RateLimitHeaders build_cors_headers build_standard_headers " + "validate_sort_field validate_sort_order build_sort_params filter_fields exclude_fields sanitize_response " + "merge_responses get_client_ip get_user_agent build_request_metadata" +).split(): + _LAZY_EXPORTS[_name] = ("api_utils", _name) + +for _name in ( + "Event EventPriority EventBus AsyncEventBus event_handler publish_event get_global_event_bus " + "set_global_event_bus EventFilter EventAggregator EventRouter" +).split(): + _LAZY_EXPORTS[_name] = ("events", _name) + +for _name in ( + "Job JobStatus JobPriority TaskQueue JobScheduler BackgroundTaskManager WorkerPool debounce throttle" +).split(): + _LAZY_EXPORTS[_name] = ("queue_manager", _name) + +for _name in ( + "StateTransition StateTransitionError StatePersistenceError StateMachine ConfigurableStateMachine " + "StatePersistence AsyncStateMachine StateMonitor StateValidator StateSnapshot" +).split(): + _LAZY_EXPORTS[_name] = ("state", _name) + +for _name in ( + "MockFactory TestDataGenerator TestHelpers MockResponse MockDatabase MockCache mock_async_call " + "create_mock_config create_test_scenario" +).split(): + _LAZY_EXPORTS[_name] = ("testing", _name) + + +def __getattr__(name: str) -> Any: + if name not in _LAZY_EXPORTS: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + module_name, attribute_name = _LAZY_EXPORTS[name] + module = import_module(f".{module_name}", __name__) + value = getattr(module, attribute_name) + globals()[name] = value + return value + + __all__ = [ - # Logging "get_logger", "setup_logger", - # Constants "DATA_DIR", "CONFIG_DIR", "LOG_DIR", @@ -266,7 +208,6 @@ __all__ = [ "AGENT_COORDINATOR_PORT", "MARKETPLACE_PORT", "PACKAGE_VERSION", - # Exceptions "AITBCError", "ConfigurationError", "NetworkError", @@ -278,14 +219,12 @@ __all__ = [ "RetryError", "CircuitBreakerOpenError", "RateLimitError", - # Environment helpers "get_env_var", "get_required_env_var", "get_bool_env_var", "get_int_env_var", "get_float_env_var", "get_list_env_var", - # Path utilities "get_data_path", "get_config_path", "get_log_path", @@ -296,192 +235,5 @@ __all__ = [ "get_keystore_path", "get_blockchain_data_path", "get_marketplace_data_path", - # JSON utilities - "load_json", - "save_json", - "merge_json", - "json_to_string", - "string_to_json", - "get_nested_value", - "set_nested_value", - "flatten_json", - # HTTP client - "AITBCHTTPClient", - "AsyncAITBCHTTPClient", - # Configuration - "BaseAITBCConfig", - "AITBCConfig", - # Decorators - "retry", - "timing", - "cache_result", - "validate_args", - "handle_exceptions", - "async_timing", - # Validators - "validate_address", - "validate_hash", - "validate_url", - "validate_port", - "validate_email", - "validate_non_empty", - "validate_positive_number", - "validate_range", - "validate_chain_id", - "validate_uuid", - # Async helpers - "run_sync", - "gather_with_concurrency", - "run_with_timeout", - "batch_process", - "sync_to_async", - "async_to_sync", - "retry_async", - "wait_for_condition", - # Database - "DatabaseConnection", - "get_database_connection", - "ensure_database", - "vacuum_database", - "get_table_info", - "table_exists", - # Data layer - "DataLayer", - "MockDataGenerator", - "RealDataFetcher", - "get_data_layer", - # Monitoring - "MetricsCollector", - "PerformanceTimer", - "HealthChecker", - # Cryptography - "derive_ethereum_address", - "sign_transaction_hash", - "verify_signature", - "encrypt_private_key", - "decrypt_private_key", - "generate_secure_random_bytes", - "keccak256_hash", - "sha256_hash", - "validate_ethereum_address", - "generate_ethereum_private_key", - # Web3 utilities - "Web3Client", - "create_web3_client", - # Security - "generate_token", - "generate_api_key", - "validate_token_format", - "validate_api_key", - "SessionManager", - "APIKeyManager", - "generate_secure_random_string", - "generate_secure_random_int", - "SecretManager", - "hash_password", - "verify_password", - "generate_nonce", - "generate_hmac", - "verify_hmac", - # Time utilities - "get_utc_now", - "get_timestamp_utc", - "format_iso8601", - "parse_iso8601", - "timestamp_to_iso", - "iso_to_timestamp", - "format_duration", - "format_duration_precise", - "parse_duration", - "add_duration", - "subtract_duration", - "get_time_until", - "get_time_since", - "calculate_deadline", - "is_deadline_passed", - "get_deadline_remaining", - "format_time_ago", - "format_time_in", - "to_timezone", - "get_timezone_offset", - "is_business_hours", - "get_start_of_day", - "get_end_of_day", - "get_start_of_week", - "get_end_of_week", - "get_start_of_month", - "get_end_of_month", - "sleep_until", - "retry_until_deadline", - "Timer", - # API utilities - "APIResponse", - "PaginatedResponse", - "success_response", - "error_response", - "not_found_response", - "unauthorized_response", - "forbidden_response", - "validation_error_response", - "conflict_response", - "internal_error_response", - "PaginationParams", - "paginate_items", - "build_paginated_response", - "RateLimitHeaders", - "build_cors_headers", - "build_standard_headers", - "validate_sort_field", - "validate_sort_order", - "build_sort_params", - "filter_fields", - "exclude_fields", - "sanitize_response", - "merge_responses", - "get_client_ip", - "get_user_agent", - "build_request_metadata", - # Events - "Event", - "EventPriority", - "EventBus", - "AsyncEventBus", - "event_handler", - "publish_event", - "get_global_event_bus", - "set_global_event_bus", - "EventFilter", - "EventAggregator", - "EventRouter", - # Queue - "Job", - "JobStatus", - "JobPriority", - "TaskQueue", - "JobScheduler", - "BackgroundTaskManager", - "WorkerPool", - "debounce", - "throttle", - # State - "StateTransition", - "StateTransitionError", - "StatePersistenceError", - "StateMachine", - "ConfigurableStateMachine", - "StatePersistence", - "AsyncStateMachine", - "StateMonitor", - "StateValidator", - "StateSnapshot", - # Testing - "MockFactory", - "TestDataGenerator", - "TestHelpers", - "MockResponse", - "MockDatabase", - "MockCache", - "mock_async_call", - "create_mock_config", - "create_test_scenario", + *_LAZY_EXPORTS.keys(), ] diff --git a/apps/agent-coordinator/src/app/exceptions.py b/apps/agent-coordinator/src/app/exceptions.py new file mode 100644 index 00000000..ea3b280d --- /dev/null +++ b/apps/agent-coordinator/src/app/exceptions.py @@ -0,0 +1,31 @@ +from datetime import datetime + +from aitbc import get_logger +from fastapi.responses import JSONResponse + +logger = get_logger(__name__) + + +def register_exception_handlers(app): + @app.exception_handler(404) + async def not_found_handler(request, exc): + return JSONResponse( + status_code=404, + content={ + "status": "error", + "message": "Resource not found", + "timestamp": datetime.utcnow().isoformat(), + }, + ) + + @app.exception_handler(500) + async def internal_error_handler(request, exc): + logger.error(f"Internal server error: {exc}") + return JSONResponse( + status_code=500, + content={ + "status": "error", + "message": "Internal server error", + "timestamp": datetime.utcnow().isoformat(), + }, + ) diff --git a/apps/agent-coordinator/src/app/lifespan.py b/apps/agent-coordinator/src/app/lifespan.py new file mode 100644 index 00000000..e39728dd --- /dev/null +++ b/apps/agent-coordinator/src/app/lifespan.py @@ -0,0 +1,40 @@ +import asyncio +from contextlib import asynccontextmanager + +from aitbc import get_logger +from fastapi import FastAPI + +from . import state +from .protocols.communication import CommunicationManager +from .protocols.message_types import MessageProcessor +from .routing.agent_discovery import AgentDiscoveryService, AgentRegistry +from .routing.load_balancer import LoadBalancer, LoadBalancingStrategy, TaskDistributor + +logger = get_logger(__name__) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + logger.info("Starting AITBC Agent Coordinator...") + + state.agent_registry = AgentRegistry() + await state.agent_registry.start() + + state.discovery_service = AgentDiscoveryService(state.agent_registry) + state.load_balancer = LoadBalancer(state.agent_registry) + state.load_balancer.set_strategy(LoadBalancingStrategy.LEAST_CONNECTIONS) + state.task_distributor = TaskDistributor(state.load_balancer) + state.communication_manager = CommunicationManager("agent-coordinator") + state.message_processor = MessageProcessor("agent-coordinator") + + asyncio.create_task(state.task_distributor.start_distribution()) + asyncio.create_task(state.message_processor.start_processing()) + + logger.info("Agent Coordinator started successfully") + + yield + + logger.info("Shutting down AITBC Agent Coordinator...") + if state.agent_registry: + await state.agent_registry.stop() + logger.info("Agent Coordinator shut down") diff --git a/apps/agent-coordinator/src/app/main.py b/apps/agent-coordinator/src/app/main.py index be83b1d7..71f4df38 100644 --- a/apps/agent-coordinator/src/app/main.py +++ b/apps/agent-coordinator/src/app/main.py @@ -1,1476 +1,50 @@ -""" -Main FastAPI Application for AITBC Agent Coordinator -""" - -import asyncio -from contextlib import asynccontextmanager -from datetime import datetime -from typing import Dict, List, Optional, Any -import uuid - -from aitbc import get_logger - -from fastapi import FastAPI, HTTPException, BackgroundTasks, Depends, status, Query -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse, Response -from pydantic import BaseModel, Field import uvicorn -import time +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware -from .protocols.communication import CommunicationManager, create_protocol, MessageType -from .protocols.message_types import MessageProcessor, create_task_message, create_status_message -from .routing.agent_discovery import AgentRegistry, AgentDiscoveryService, create_agent_info -from .routing.load_balancer import LoadBalancer, TaskDistributor, TaskPriority, LoadBalancingStrategy -from .ai.realtime_learning import learning_system -from .ai.advanced_ai import ai_integration -from .consensus.distributed_consensus import distributed_consensus -from .auth.jwt_handler import jwt_handler, password_manager, api_key_manager -from .auth.middleware import get_current_user, require_permissions, require_role, security_headers -from .auth.permissions import permission_manager, Permission, Role -from .monitoring.prometheus_metrics import metrics_registry, performance_monitor -from .monitoring.alerting import alert_manager, SLAMonitor from .config import settings - -# Configure logging -logger = get_logger(__name__) - -# Global variables -agent_registry: Optional[AgentRegistry] = None -discovery_service: Optional[AgentDiscoveryService] = None -load_balancer: Optional[LoadBalancer] = None -task_distributor: Optional[TaskDistributor] = None -communication_manager: Optional[CommunicationManager] = None -message_processor: Optional[MessageProcessor] = None - -@asynccontextmanager -async def lifespan(app: FastAPI): - """Application lifespan management""" - # Startup - logger.info("Starting AITBC Agent Coordinator...") - - # Initialize services - global agent_registry, discovery_service, load_balancer, task_distributor, communication_manager, message_processor - - # Start agent registry - agent_registry = AgentRegistry() - await agent_registry.start() - - # Initialize discovery service - discovery_service = AgentDiscoveryService(agent_registry) - - # Initialize load balancer - load_balancer = LoadBalancer(agent_registry) - load_balancer.set_strategy(LoadBalancingStrategy.LEAST_CONNECTIONS) - - # Initialize task distributor - task_distributor = TaskDistributor(load_balancer) - - # Initialize communication manager - communication_manager = CommunicationManager("agent-coordinator") - - # Initialize message processor - message_processor = MessageProcessor("agent-coordinator") - - # Start background tasks - asyncio.create_task(task_distributor.start_distribution()) - asyncio.create_task(message_processor.start_processing()) - - logger.info("Agent Coordinator started successfully") - - yield - - # Shutdown - logger.info("Shutting down AITBC Agent Coordinator...") - - if agent_registry: - await agent_registry.stop() - - logger.info("Agent Coordinator shut down") - -# Create FastAPI app -app = FastAPI( - title="AITBC Agent Coordinator", - description="Advanced multi-agent coordination and management system", - version="1.0.0", - lifespan=lifespan -) - -# Add CORS middleware -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# Pydantic models -class AgentRegistrationRequest(BaseModel): - agent_id: str = Field(..., description="Unique agent identifier") - agent_type: str = Field(..., description="Type of agent") - capabilities: List[str] = Field(default_factory=list, description="Agent capabilities") - services: List[str] = Field(default_factory=list, description="Available services") - endpoints: Dict[str, str] = Field(default_factory=dict, description="Service endpoints") - metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata") - -class AgentStatusUpdate(BaseModel): - status: str = Field(..., description="Agent status") - load_metrics: Dict[str, float] = Field(default_factory=dict, description="Load metrics") - -class TaskSubmission(BaseModel): - task_data: Dict[str, Any] = Field(..., description="Task data") - priority: str = Field("normal", description="Task priority") - requirements: Optional[Dict[str, Any]] = Field(None, description="Task requirements") - -class MessageRequest(BaseModel): - receiver_id: str = Field(..., description="Receiver agent ID") - message_type: str = Field(..., description="Message type") - payload: Dict[str, Any] = Field(..., description="Message payload") - priority: str = Field("normal", description="Message priority") - -# Health check endpoint -@app.get("/health") -async def health_check(): - """Health check endpoint""" - return { - "status": "healthy", - "service": "agent-coordinator", - "timestamp": datetime.utcnow().isoformat(), - "version": "1.0.0" - } - -# Root endpoint -@app.get("/") -async def root(): - """Root endpoint with service information""" - return { - "service": "AITBC Agent Coordinator", - "description": "Advanced multi-agent coordination and management system", - "version": "1.0.0", - "endpoints": [ - "/health", - "/agents/register", - "/agents/discover", - "/agents/{agent_id}", - "/agents/{agent_id}/status", - "/tasks/submit", - "/tasks/status", - "/messages/send", - "/load-balancer/stats", - "/registry/stats" - ] - } - -# Agent registration -@app.post("/agents/register") -async def register_agent(request: AgentRegistrationRequest): - """Register a new agent""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - # Create agent info with validation - try: - agent_info = create_agent_info( - agent_id=request.agent_id, - agent_type=request.agent_type, - capabilities=request.capabilities, - services=request.services, - endpoints=request.endpoints - ) - agent_info.metadata = request.metadata - except ValueError as e: - raise HTTPException(status_code=422, detail=str(e)) - - # Register agent - success = await agent_registry.register_agent(agent_info) - - if success: - return { - "status": "success", - "message": f"Agent {request.agent_id} registered successfully", - "agent_id": request.agent_id, - "registered_at": datetime.utcnow().isoformat() - } - else: - raise HTTPException(status_code=500, detail="Failed to register agent") - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error registering agent: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Agent discovery -@app.post("/agents/discover") -async def discover_agents(query: Dict[str, Any]): - """Discover agents based on criteria""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - agents = await agent_registry.discover_agents(query) - - return { - "status": "success", - "query": query, - "agents": [agent.to_dict() for agent in agents], - "count": len(agents), - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error discovering agents: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Get agent by ID -@app.get("/agents/{agent_id}") -async def get_agent(agent_id: str): - """Get agent information by ID""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - agent = await agent_registry.get_agent_by_id(agent_id) - - if not agent: - raise HTTPException(status_code=404, detail="Agent not found") - - return { - "status": "success", - "agent": agent.to_dict(), - "timestamp": datetime.utcnow().isoformat() - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting agent: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Update agent status -@app.put("/agents/{agent_id}/status") -async def update_agent_status(agent_id: str, request: AgentStatusUpdate): - """Update agent status""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - from .routing.agent_discovery import AgentStatus - - success = await agent_registry.update_agent_status( - agent_id, - AgentStatus(request.status), - request.load_metrics - ) - - if success: - return { - "status": "success", - "message": f"Agent {agent_id} status updated", - "agent_id": agent_id, - "new_status": request.status, - "updated_at": datetime.utcnow().isoformat() - } - else: - raise HTTPException(status_code=500, detail="Failed to update agent status") - - except Exception as e: - logger.error(f"Error updating agent status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Submit task -@app.post("/tasks/submit") -async def submit_task(request: TaskSubmission, background_tasks: BackgroundTasks): - """Submit a task for distribution""" - try: - if not task_distributor: - raise HTTPException(status_code=503, detail="Task distributor not available") - - # Convert priority string to enum - try: - priority = TaskPriority(request.priority.lower()) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid priority: {request.priority}") - - # Submit task - await task_distributor.submit_task( - request.task_data, - priority, - request.requirements - ) - - return { - "status": "success", - "message": "Task submitted successfully", - "task_id": request.task_data.get("task_id", str(uuid.uuid4())), - "priority": request.priority, - "submitted_at": datetime.utcnow().isoformat() - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error submitting task: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Get task status -@app.get("/tasks/status") -async def get_task_status(): - """Get task distribution statistics""" - try: - if not task_distributor: - raise HTTPException(status_code=503, detail="Task distributor not available") - - stats = task_distributor.get_distribution_stats() - - return { - "status": "success", - "stats": stats, - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error getting task status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Send message -@app.post("/messages/send") -async def send_message(request: MessageRequest): - """Send message to agent""" - try: - if not communication_manager: - raise HTTPException(status_code=503, detail="Communication manager not available") - - from .protocols.communication import AgentMessage, Priority - - # Convert message type - try: - message_type = MessageType(request.message_type) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid message type: {request.message_type}") - - # Convert priority - try: - priority = Priority(request.priority.lower()) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid priority: {request.priority}") - - # Create message - message = AgentMessage( - sender_id="agent-coordinator", - receiver_id=request.receiver_id, - message_type=message_type, - priority=priority, - payload=request.payload - ) - - # Send message - success = await communication_manager.send_message("hierarchical", message) - - if success: - return { - "status": "success", - "message": "Message sent successfully", - "message_id": message.id, - "receiver_id": request.receiver_id, - "sent_at": datetime.utcnow().isoformat() - } - else: - raise HTTPException(status_code=500, detail="Failed to send message") - - except Exception as e: - logger.error(f"Error sending message: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Load balancer statistics -@app.get("/load-balancer/stats") -async def get_load_balancer_stats(): - """Get load balancer statistics""" - try: - if not load_balancer: - raise HTTPException(status_code=503, detail="Load balancer not available") - - stats = load_balancer.get_load_balancing_stats() - - return { - "status": "success", - "stats": stats, - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error getting load balancer stats: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Registry statistics -@app.get("/registry/stats") -async def get_registry_stats(): - """Get agent registry statistics""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - stats = await agent_registry.get_registry_stats() - - return { - "status": "success", - "stats": stats, - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error getting registry stats: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Get agents by service -@app.get("/agents/service/{service}") -async def get_agents_by_service(service: str): - """Get agents that provide a specific service""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - agents = await agent_registry.get_agents_by_service(service) - - return { - "status": "success", - "service": service, - "agents": [agent.to_dict() for agent in agents], - "count": len(agents), - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error getting agents by service: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Get agents by capability -@app.get("/agents/capability/{capability}") -async def get_agents_by_capability(capability: str): - """Get agents that have a specific capability""" - try: - if not agent_registry: - raise HTTPException(status_code=503, detail="Agent registry not available") - - agents = await agent_registry.get_agents_by_capability(capability) - - return { - "status": "success", - "capability": capability, - "agents": [agent.to_dict() for agent in agents], - "count": len(agents), - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error getting agents by capability: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Set load balancing strategy -@app.put("/load-balancer/strategy") -async def set_load_balancing_strategy(strategy: str = Query(..., description="Load balancing strategy")): - """Set load balancing strategy""" - try: - if not load_balancer: - raise HTTPException(status_code=503, detail="Load balancer not available") - - try: - load_balancing_strategy = LoadBalancingStrategy(strategy.lower()) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid strategy: {strategy}") - - load_balancer.set_strategy(load_balancing_strategy) - - return { - "status": "success", - "message": f"Load balancing strategy set to {strategy}", - "strategy": strategy, - "updated_at": datetime.utcnow().isoformat() - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error setting load balancing strategy: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Advanced AI/ML endpoints -@app.post("/ai/learning/experience") -async def record_learning_experience(experience_data: Dict[str, Any]): - """Record a learning experience for the AI system""" - try: - result = await learning_system.record_experience(experience_data) - return result - except Exception as e: - logger.error(f"Error recording learning experience: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/ai/learning/statistics") -async def get_learning_statistics(): - """Get learning system statistics""" - try: - result = await learning_system.get_learning_statistics() - return result - except Exception as e: - logger.error(f"Error getting learning statistics: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/learning/predict") -async def predict_performance(context: Dict[str, Any], action: str = Query(...)): - """Predict performance for a given action""" - try: - result = await learning_system.predict_performance(context, action) - return result - except Exception as e: - logger.error(f"Error predicting performance: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/learning/recommend") -async def recommend_action(context: Dict[str, Any], available_actions: List[str]): - """Get AI-recommended action""" - try: - result = await learning_system.recommend_action(context, available_actions) - return result - except Exception as e: - logger.error(f"Error recommending action: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/neural-network/create") -async def create_neural_network(config: Dict[str, Any]): - """Create a new neural network""" - try: - result = await ai_integration.create_neural_network(config) - return result - except Exception as e: - logger.error(f"Error creating neural network: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/neural-network/{network_id}/train") -async def train_neural_network(network_id: str, training_data: List[Dict[str, Any]], epochs: int = 100): - """Train a neural network""" - try: - result = await ai_integration.train_neural_network(network_id, training_data, epochs) - return result - except Exception as e: - logger.error(f"Error training neural network: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/neural-network/{network_id}/predict") -async def predict_with_neural_network(network_id: str, features: List[float]): - """Make prediction with neural network""" - try: - result = await ai_integration.predict_with_neural_network(network_id, features) - return result - except Exception as e: - logger.error(f"Error predicting with neural network: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/ml-model/create") -async def create_ml_model(config: Dict[str, Any]): - """Create a new ML model""" - try: - result = await ai_integration.create_ml_model(config) - return result - except Exception as e: - logger.error(f"Error creating ML model: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/ml-model/{model_id}/train") -async def train_ml_model(model_id: str, training_data: List[Dict[str, Any]]): - """Train an ML model""" - try: - result = await ai_integration.train_ml_model(model_id, training_data) - return result - except Exception as e: - logger.error(f"Error training ML model: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/ai/ml-model/{model_id}/predict") -async def predict_with_ml_model(model_id: str, features: List[float]): - """Make prediction with ML model""" - try: - result = await ai_integration.predict_with_ml_model(model_id, features) - return result - except Exception as e: - logger.error(f"Error predicting with ML model: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/ai/statistics") -async def get_ai_statistics(): - """Get comprehensive AI/ML statistics""" - try: - result = await ai_integration.get_ai_statistics() - return result - except Exception as e: - logger.error(f"Error getting AI statistics: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Distributed consensus endpoints -@app.post("/consensus/node/register") -async def register_consensus_node(node_data: Dict[str, Any]): - """Register a node in the consensus network""" - try: - result = await distributed_consensus.register_node(node_data) - return result - except Exception as e: - logger.error(f"Error registering consensus node: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/consensus/proposal/create") -async def create_consensus_proposal(proposal_data: Dict[str, Any]): - """Create a new consensus proposal""" - try: - result = await distributed_consensus.create_proposal(proposal_data) - return result - except Exception as e: - logger.error(f"Error creating consensus proposal: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/consensus/proposal/{proposal_id}/vote") -async def cast_consensus_vote(proposal_id: str, node_id: str, vote: bool): - """Cast a vote for a proposal""" - try: - result = await distributed_consensus.cast_vote(proposal_id, node_id, vote) - return result - except Exception as e: - logger.error(f"Error casting consensus vote: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/consensus/proposal/{proposal_id}") -async def get_proposal_status(proposal_id: str): - """Get proposal status""" - try: - result = await distributed_consensus.get_proposal_status(proposal_id) - return result - except Exception as e: - logger.error(f"Error getting proposal status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.put("/consensus/algorithm") -async def set_consensus_algorithm(algorithm: str = Query(..., description="Consensus algorithm")): - """Set the consensus algorithm""" - try: - result = await distributed_consensus.set_consensus_algorithm(algorithm) - return result - except Exception as e: - logger.error(f"Error setting consensus algorithm: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/consensus/statistics") -async def get_consensus_statistics(): - """Get consensus statistics""" - try: - result = await distributed_consensus.get_consensus_statistics() - return result - except Exception as e: - logger.error(f"Error getting consensus statistics: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.put("/consensus/node/{node_id}/status") -async def update_node_status(node_id: str, is_active: bool): - """Update node status""" - try: - result = await distributed_consensus.update_node_status(node_id, is_active) - return result - except Exception as e: - logger.error(f"Error updating node status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Advanced features status endpoint -@app.get("/advanced-features/status") -async def get_advanced_features_status(): - """Get status of all advanced features""" - try: - learning_stats = await learning_system.get_learning_statistics() - ai_stats = await ai_integration.get_ai_statistics() - consensus_stats = await distributed_consensus.get_consensus_statistics() - - return { - "status": "success", - "timestamp": datetime.utcnow().isoformat(), - "features": { - "realtime_learning": { - "status": "active", - "experiences": learning_stats.get("total_experiences", 0), - "learning_rate": learning_stats.get("learning_rate", 0.01), - "models": learning_stats.get("models_count", 0) - }, - "advanced_ai": { - "status": "active", - "models": ai_stats.get("total_models", 0), - "neural_networks": ai_stats.get("total_neural_networks", 0), - "predictions": ai_stats.get("total_predictions", 0) - }, - "distributed_consensus": { - "status": "active", - "nodes": consensus_stats.get("active_nodes", 0), - "proposals": consensus_stats.get("total_proposals", 0), - "success_rate": consensus_stats.get("success_rate", 0.0), - "algorithm": consensus_stats.get("current_algorithm", "majority_vote") - } - } - } - except Exception as e: - logger.error(f"Error getting advanced features status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Authentication endpoints -@app.post("/auth/login") -async def login(login_data: Dict[str, str]): - """User login with username and password""" - try: - username = login_data.get("username") - password = login_data.get("password") - - if not username or not password: - raise HTTPException(status_code=422, detail="Username and password are required") - - # In a real implementation, verify credentials against database - # For demo, we'll create a simple user - import os - - demo_users = { - "admin": os.getenv("DEMO_ADMIN_PASSWORD", "admin123"), - "operator": os.getenv("DEMO_OPERATOR_PASSWORD", "operator123"), - "user": os.getenv("DEMO_USER_PASSWORD", "user123") - } - - if username == "admin" and password == demo_users["admin"]: - user_id = "admin_001" - role = Role.ADMIN - elif username == "operator" and password == demo_users["operator"]: - user_id = "operator_001" - role = Role.OPERATOR - elif username == "user" and password == demo_users["user"]: - user_id = "user_001" - role = Role.USER - else: - raise HTTPException(status_code=401, detail="Invalid credentials") - - # Assign role to user - permission_manager.assign_role(user_id, role) - - # Generate JWT token - token_result = jwt_handler.generate_token({ - "user_id": user_id, - "username": username, - "role": role.value, - "permissions": [perm.value for perm in permission_manager.user_permissions.get(user_id, set())] - }) - - # Generate refresh token - refresh_result = jwt_handler.generate_refresh_token({ - "user_id": user_id, - "username": username, - "role": role.value - }) - - return { - "status": "success", - "user_id": user_id, - "username": username, - "role": role.value, - "access_token": token_result["token"], - "refresh_token": refresh_result["refresh_token"], - "expires_at": token_result["expires_at"], - "token_type": token_result["token_type"] - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error during login: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/auth/refresh") -async def refresh_token(refresh_data: Dict[str, str]): - """Refresh access token using refresh token""" - try: - refresh_token = refresh_data.get("refresh_token") - - if not refresh_token: - raise HTTPException(status_code=422, detail="Refresh token is required") - - result = jwt_handler.refresh_access_token(refresh_token) - - if result["status"] == "error": - raise HTTPException(status_code=401, detail=result["message"]) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error refreshing token: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/auth/validate") -async def validate_token(validate_data: Dict[str, str]): - """Validate JWT token""" - try: - token = validate_data.get("token") - - if not token: - raise HTTPException(status_code=422, detail="Token is required") - - result = jwt_handler.validate_token(token) - - if not result["valid"]: - raise HTTPException(status_code=401, detail=result["message"]) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error validating token: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/auth/api-key/generate") -async def generate_api_key( - user_id: str, - permissions: List[str] = None, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Generate API key for user""" - try: - # Check if user has permission to generate API keys - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = api_key_manager.generate_api_key(user_id, permissions) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error generating API key: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/auth/api-key/validate") -async def validate_api_key(api_key: str): - """Validate API key""" - try: - result = api_key_manager.validate_api_key(api_key) - - if not result["valid"]: - raise HTTPException(status_code=401, detail="Invalid API key") - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error validating API key: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.delete("/auth/api-key/{api_key}") -async def revoke_api_key( - api_key: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Revoke API key""" - try: - # Check if user has permission to manage API keys - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = api_key_manager.revoke_api_key(api_key) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error revoking API key: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# User management endpoints -@app.post("/users/{user_id}/role") -async def assign_user_role( - user_id: str, - role: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Assign role to user""" - try: - # Check if user has permission to manage roles - if not permission_manager.has_permission(current_user["user_id"], Permission.USER_MANAGE_ROLES): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - try: - role_enum = Role(role.lower()) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid role: {role}") - - result = permission_manager.assign_role(user_id, role_enum) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error assigning user role: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/users/{user_id}/role") -async def get_user_role( - user_id: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Get user's role""" - try: - # Check if user has permission to view users - if not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = permission_manager.get_user_role(user_id) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting user role: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/users/{user_id}/permissions") -async def get_user_permissions( - user_id: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Get user's permissions""" - try: - # Users can view their own permissions, admins can view any - if user_id != current_user["user_id"] and not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = permission_manager.get_user_permissions(user_id) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting user permissions: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/users/{user_id}/permissions/grant") -async def grant_user_permission( - user_id: str, - permission: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Grant custom permission to user""" - try: - # Check if user has permission to manage permissions - if not permission_manager.has_permission(current_user["user_id"], Permission.USER_MANAGE_ROLES): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - try: - permission_enum = Permission(permission) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid permission: {permission}") - - result = permission_manager.grant_custom_permission(user_id, permission_enum) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error granting user permission: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.delete("/users/{user_id}/permissions/{permission}") -async def revoke_user_permission( - user_id: str, - permission: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Revoke custom permission from user""" - try: - # Check if user has permission to manage permissions - if not permission_manager.has_permission(current_user["user_id"], Permission.USER_MANAGE_ROLES): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - try: - permission_enum = Permission(permission) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid permission: {permission}") - - result = permission_manager.revoke_custom_permission(user_id, permission_enum) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error revoking user permission: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Role and permission management endpoints -@app.get("/roles") -async def list_all_roles(current_user: Dict[str, Any] = Depends(get_current_user)): - """List all available roles and their permissions""" - try: - # Check if user has permission to view roles - if not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = permission_manager.list_all_roles() - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error listing roles: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/roles/{role}") -async def get_role_permissions( - role: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Get all permissions for a specific role""" - try: - # Check if user has permission to view roles - if not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - try: - role_enum = Role(role.lower()) - except ValueError: - raise HTTPException(status_code=400, detail=f"Invalid role: {role}") - - result = permission_manager.get_role_permissions(role_enum) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting role permissions: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/auth/stats") -async def get_permission_stats(current_user: Dict[str, Any] = Depends(get_current_user)): - """Get statistics about permissions and users""" - try: - # Check if user has permission to view security stats - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = permission_manager.get_permission_stats() - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting permission stats: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Protected endpoint example -@app.get("/protected/admin") -@require_role([Role.ADMIN]) -async def admin_only_endpoint(current_user: Dict[str, Any] = Depends(get_current_user)): - """Admin-only endpoint example""" - return { - "status": "success", - "message": "Welcome admin!", - "user": { - "user_id": current_user.get("user_id"), - "username": current_user.get("username"), - "role": str(current_user.get("role")), - "permissions": current_user.get("permissions", []), - "auth_type": current_user.get("auth_type") - } - } - -@app.get("/protected/operator") -@require_role([Role.ADMIN, Role.OPERATOR]) -async def operator_endpoint(current_user: Dict[str, Any] = Depends(get_current_user)): - """Operator and admin endpoint example""" - return { - "status": "success", - "message": "Welcome operator!", - "user": { - "user_id": current_user.get("user_id"), - "username": current_user.get("username"), - "role": str(current_user.get("role")), - "permissions": current_user.get("permissions", []), - "auth_type": current_user.get("auth_type") - } - } - -# Monitoring and metrics endpoints -@app.get("/metrics") -async def get_prometheus_metrics(): - """Get metrics in Prometheus format""" - try: - metrics = metrics_registry.get_all_metrics() - - # Convert to Prometheus text format - prometheus_output = [] - - for name, metric_data in metrics.items(): - prometheus_output.append(f"# HELP {name} {metric_data['description']}") - prometheus_output.append(f"# TYPE {name} {metric_data['type']}") - - if metric_data['type'] == 'counter': - for labels, value in metric_data['values'].items(): - if labels != '_default': - prometheus_output.append(f"{name}{{{labels}}} {value}") - else: - prometheus_output.append(f"{name} {value}") - - elif metric_data['type'] == 'gauge': - for labels, value in metric_data['values'].items(): - if labels != '_default': - prometheus_output.append(f"{name}{{{labels}}} {value}") - else: - prometheus_output.append(f"{name} {value}") - - elif metric_data['type'] == 'histogram': - for key, count in metric_data['counts'].items(): - prometheus_output.append(f"{name}_count{{{key}}} {count}") - for key, sum_val in metric_data['sums'].items(): - prometheus_output.append(f"{name}_sum{{{key}}} {sum_val}") - - return Response( - content="\n".join(prometheus_output), - media_type="text/plain" - ) - - except Exception as e: - logger.error(f"Error getting metrics: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/metrics/summary") -async def get_metrics_summary(): - """Get metrics summary for dashboard""" - try: - summary = performance_monitor.get_performance_summary() - - # Add additional system metrics - system_metrics = { - "total_agents": len(agent_registry.agents) if agent_registry else 0, - "active_agents": len([a for a in agent_registry.agents.values() if getattr(a, 'is_active', True)]) if agent_registry else 0, - "total_tasks": len(task_distributor.task_queue._queue) if task_distributor and hasattr(task_distributor, 'task_queue') else 0, - "load_balancer_strategy": load_balancer.strategy.value if load_balancer else "unknown" - } - - return { - "status": "success", - "performance": summary, - "system": system_metrics, - "timestamp": datetime.utcnow().isoformat() - } - - except Exception as e: - logger.error(f"Error getting metrics summary: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/metrics/health") -async def get_health_metrics(): - """Get health metrics for monitoring""" - try: - # Get system health metrics - import psutil - - memory = psutil.virtual_memory() - cpu = psutil.cpu_percent(interval=1) - - # Update performance monitor with system metrics - performance_monitor.update_system_metrics(memory.used, cpu) - - health_metrics = { - "memory": { - "total": memory.total, - "available": memory.available, - "used": memory.used, - "percentage": memory.percent - }, - "cpu": { - "percentage": cpu, - "count": psutil.cpu_count() - }, - "uptime": performance_monitor.get_performance_summary()["uptime_seconds"], - "timestamp": datetime.utcnow().isoformat() - } - - return { - "status": "success", - "health": health_metrics - } - - except Exception as e: - logger.error(f"Error getting health metrics: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Alerting endpoints -@app.get("/alerts") -async def get_alerts( - status: Optional[str] = None, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Get alerts with optional status filter""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - if status == "active": - alerts = alert_manager.get_active_alerts() - else: - alerts = alert_manager.get_alert_history() - - return { - "status": "success", - "alerts": alerts, - "total": len(alerts) - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting alerts: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/alerts/{alert_id}/resolve") -async def resolve_alert( - alert_id: str, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Resolve an alert""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - result = alert_manager.resolve_alert(alert_id) - - return result - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error resolving alert: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/alerts/stats") -async def get_alert_stats(current_user: Dict[str, Any] = Depends(get_current_user)): - """Get alert statistics""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - stats = alert_manager.get_alert_stats() - - return { - "status": "success", - "stats": stats - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting alert stats: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/alerts/rules") -async def get_alert_rules(current_user: Dict[str, Any] = Depends(get_current_user)): - """Get alert rules""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - rules = [rule.to_dict() for rule in alert_manager.rules.values()] - - return { - "status": "success", - "rules": rules, - "total": len(rules) - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting alert rules: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# SLA monitoring endpoints -@app.get("/sla") -async def get_sla_status( - sla_id: Optional[str] = None, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Get SLA status""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - if sla_id: - sla_status = alert_manager.sla_monitor.get_sla_compliance(sla_id) - else: - sla_status = alert_manager.sla_monitor.get_all_sla_status() - - return { - "status": "success", - "sla": sla_status - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting SLA status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/sla/{sla_id}/record") -async def record_sla_metric( - sla_id: str, - value: float, - current_user: Dict[str, Any] = Depends(get_current_user) -): - """Record SLA metric""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - alert_manager.sla_monitor.record_metric(sla_id, value) - - return { - "status": "success", - "message": f"SLA metric recorded for {sla_id}", - "value": value, - "timestamp": datetime.utcnow().isoformat() - } - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error recording SLA metric: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# System status endpoint with monitoring -@app.get("/system/status") -async def get_system_status(current_user: Dict[str, Any] = Depends(get_current_user)): - """Get comprehensive system status""" - try: - if not permission_manager.has_permission(current_user["user_id"], Permission.SYSTEM_HEALTH): - raise HTTPException(status_code=403, detail="Insufficient permissions") - - # Get various status information - performance = performance_monitor.get_performance_summary() - alerts = alert_manager.get_active_alerts() - sla_status = alert_manager.sla_monitor.get_all_sla_status() - - # Get system health - import psutil - memory = psutil.virtual_memory() - cpu = psutil.cpu_percent(interval=1) - - status = { - "overall": "healthy" if len(alerts) == 0 else "degraded", - "performance": performance, - "alerts": { - "active_count": len(alerts), - "critical_count": len([a for a in alerts if a.get("severity") == "critical"]), - "warning_count": len([a for a in alerts if a.get("severity") == "warning"]) - }, - "sla": { - "overall_compliance": sla_status.get("overall_compliance", 100.0), - "total_slas": sla_status.get("total_slas", 0) - }, - "system": { - "memory_usage": memory.percent, - "cpu_usage": cpu, - "uptime": performance["uptime_seconds"] - }, - "services": { - "agent_coordinator": "running", - "agent_registry": "running" if agent_registry else "stopped", - "load_balancer": "running" if load_balancer else "stopped", - "task_distributor": "running" if task_distributor else "stopped" - }, - "timestamp": datetime.utcnow().isoformat() - } - - return status - - except HTTPException: - raise - except Exception as e: - logger.error(f"Error getting system status: {e}") - raise HTTPException(status_code=500, detail=str(e)) - -# Add middleware to record metrics for all requests -@app.middleware("http") -async def metrics_middleware(request, call_next): - """Middleware to record request metrics""" - start_time = time.time() - - response = await call_next(request) - - # Record request metrics - duration = time.time() - start_time - performance_monitor.record_request( - method=request.method, - endpoint=request.url.path, - status_code=response.status_code, - duration=duration - ) - - return response - -# Add security headers middleware -@app.middleware("http") -async def security_headers_middleware(request, call_next): - """Middleware to add security headers""" - response = await call_next(request) - - headers = security_headers.get_security_headers() - for header, value in headers.items(): - response.headers[header] = value - - return response - -# Error handlers -@app.exception_handler(404) -async def not_found_handler(request, exc): - return JSONResponse( - status_code=404, - content={ - "status": "error", - "message": "Resource not found", - "timestamp": datetime.utcnow().isoformat() - } +from .exceptions import register_exception_handlers +from .lifespan import lifespan +from .middleware import register_middleware +from .routers import ROUTERS + + +def create_app() -> FastAPI: + app = FastAPI( + title="AITBC Agent Coordinator", + description="Advanced multi-agent coordination and management system", + version="1.0.0", + lifespan=lifespan, ) -@app.exception_handler(500) -async def internal_error_handler(request, exc): - logger.error(f"Internal server error: {exc}") - return JSONResponse( - status_code=500, - content={ - "status": "error", - "message": "Internal server error", - "timestamp": datetime.utcnow().isoformat() - } + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], ) -# Main function + for router in ROUTERS: + app.include_router(router) + + register_middleware(app) + register_exception_handlers(app) + return app + + +app = create_app() + + def main(): - """Main function to run the application""" uvicorn.run( - "main:app", + "app.main:app", host=settings.host, port=settings.port, reload=True, - log_level="info" + log_level="info", ) + if __name__ == "__main__": main() diff --git a/apps/agent-coordinator/src/app/middleware.py b/apps/agent-coordinator/src/app/middleware.py new file mode 100644 index 00000000..5d3b1cd3 --- /dev/null +++ b/apps/agent-coordinator/src/app/middleware.py @@ -0,0 +1,27 @@ +import time + +from .auth.middleware import security_headers +from .monitoring.prometheus_metrics import performance_monitor + + +def register_middleware(app): + @app.middleware("http") + async def metrics_middleware(request, call_next): + start_time = time.time() + response = await call_next(request) + duration = time.time() - start_time + performance_monitor.record_request( + method=request.method, + endpoint=request.url.path, + status_code=response.status_code, + duration=duration, + ) + return response + + @app.middleware("http") + async def security_headers_middleware(request, call_next): + response = await call_next(request) + headers = security_headers.get_security_headers() + for header, value in headers.items(): + response.headers[header] = value + return response diff --git a/apps/agent-coordinator/src/app/models.py b/apps/agent-coordinator/src/app/models.py new file mode 100644 index 00000000..f169d162 --- /dev/null +++ b/apps/agent-coordinator/src/app/models.py @@ -0,0 +1,30 @@ +from typing import Any, Dict, List, Optional + +from pydantic import BaseModel, Field + + +class AgentRegistrationRequest(BaseModel): + agent_id: str = Field(..., description="Unique agent identifier") + agent_type: str = Field(..., description="Type of agent") + capabilities: List[str] = Field(default_factory=list, description="Agent capabilities") + services: List[str] = Field(default_factory=list, description="Available services") + endpoints: Dict[str, str] = Field(default_factory=dict, description="Service endpoints") + metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata") + + +class AgentStatusUpdate(BaseModel): + status: str = Field(..., description="Agent status") + load_metrics: Dict[str, float] = Field(default_factory=dict, description="Load metrics") + + +class TaskSubmission(BaseModel): + task_data: Dict[str, Any] = Field(..., description="Task data") + priority: str = Field("normal", description="Task priority") + requirements: Optional[Dict[str, Any]] = Field(None, description="Task requirements") + + +class MessageRequest(BaseModel): + receiver_id: str = Field(..., description="Receiver agent ID") + message_type: str = Field(..., description="Message type") + payload: Dict[str, Any] = Field(..., description="Message payload") + priority: str = Field("normal", description="Message priority") diff --git a/apps/agent-coordinator/src/app/routers/__init__.py b/apps/agent-coordinator/src/app/routers/__init__.py new file mode 100644 index 00000000..d832fac3 --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/__init__.py @@ -0,0 +1,14 @@ +from . import agents, ai, alerts, auth, consensus, health, messages, monitoring, tasks, users + +ROUTERS = [ + health.router, + agents.router, + tasks.router, + messages.router, + ai.router, + consensus.router, + auth.router, + users.router, + monitoring.router, + alerts.router, +] diff --git a/apps/agent-coordinator/src/app/routers/agents.py b/apps/agent-coordinator/src/app/routers/agents.py new file mode 100644 index 00000000..064a8407 --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/agents.py @@ -0,0 +1,142 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Agent registration +@router.post("/agents/register") +async def register_agent(request: AgentRegistrationRequest): + """Register a new agent""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + # Create agent info with validation + try: + agent_info = create_agent_info( + agent_id=request.agent_id, + agent_type=request.agent_type, + capabilities=request.capabilities, + services=request.services, + endpoints=request.endpoints + ) + agent_info.metadata = request.metadata + except ValueError as e: + raise HTTPException(status_code=422, detail=str(e)) + + # Register agent + success = await state.agent_registry.register_agent(agent_info) + + if success: + return { + "status": "success", + "message": f"Agent {request.agent_id} registered successfully", + "agent_id": request.agent_id, + "registered_at": datetime.utcnow().isoformat() + } + else: + raise HTTPException(status_code=500, detail="Failed to register agent") + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error registering agent: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Agent discovery +@router.post("/agents/discover") +async def discover_agents(query: Dict[str, Any]): + """Discover agents based on criteria""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + agents = await state.agent_registry.discover_agents(query) + + return { + "status": "success", + "query": query, + "agents": [agent.to_dict() for agent in agents], + "count": len(agents), + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error discovering agents: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Get agent by ID +@router.get("/agents/{agent_id}") +async def get_agent(agent_id: str): + """Get agent information by ID""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + agent = await state.agent_registry.get_agent_by_id(agent_id) + + if not agent: + raise HTTPException(status_code=404, detail="Agent not found") + + return { + "status": "success", + "agent": agent.to_dict(), + "timestamp": datetime.utcnow().isoformat() + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting agent: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Update agent status +@router.put("/agents/{agent_id}/status") +async def update_agent_status(agent_id: str, request: AgentStatusUpdate): + """Update agent status""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + from ..routing.agent_discovery import AgentStatus + + success = await state.agent_registry.update_agent_status( + agent_id, + AgentStatus(request.status), + request.load_metrics + ) + + if success: + return { + "status": "success", + "message": f"Agent {agent_id} status updated", + "agent_id": agent_id, + "new_status": request.status, + "updated_at": datetime.utcnow().isoformat() + } + else: + raise HTTPException(status_code=500, detail="Failed to update agent status") + + except Exception as e: + logger.error(f"Error updating agent status: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/ai.py b/apps/agent-coordinator/src/app/routers/ai.py new file mode 100644 index 00000000..30361b7e --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/ai.py @@ -0,0 +1,135 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Advanced AI/ML endpoints +@router.post("/ai/learning/experience") +async def record_learning_experience(experience_data: Dict[str, Any]): + """Record a learning experience for the AI system""" + try: + result = await learning_system.record_experience(experience_data) + return result + except Exception as e: + logger.error(f"Error recording learning experience: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/ai/learning/statistics") +async def get_learning_statistics(): + """Get learning system statistics""" + try: + result = await learning_system.get_learning_statistics() + return result + except Exception as e: + logger.error(f"Error getting learning statistics: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/learning/predict") +async def predict_performance(context: Dict[str, Any], action: str = Query(...)): + """Predict performance for a given action""" + try: + result = await learning_system.predict_performance(context, action) + return result + except Exception as e: + logger.error(f"Error predicting performance: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/learning/recommend") +async def recommend_action(context: Dict[str, Any], available_actions: List[str]): + """Get AI-recommended action""" + try: + result = await learning_system.recommend_action(context, available_actions) + return result + except Exception as e: + logger.error(f"Error recommending action: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/neural-network/create") +async def create_neural_network(config: Dict[str, Any]): + """Create a new neural network""" + try: + result = await ai_integration.create_neural_network(config) + return result + except Exception as e: + logger.error(f"Error creating neural network: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/neural-network/{network_id}/train") +async def train_neural_network(network_id: str, training_data: List[Dict[str, Any]], epochs: int = 100): + """Train a neural network""" + try: + result = await ai_integration.train_neural_network(network_id, training_data, epochs) + return result + except Exception as e: + logger.error(f"Error training neural network: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/neural-network/{network_id}/predict") +async def predict_with_neural_network(network_id: str, features: List[float]): + """Make prediction with neural network""" + try: + result = await ai_integration.predict_with_neural_network(network_id, features) + return result + except Exception as e: + logger.error(f"Error predicting with neural network: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/ml-model/create") +async def create_ml_model(config: Dict[str, Any]): + """Create a new ML model""" + try: + result = await ai_integration.create_ml_model(config) + return result + except Exception as e: + logger.error(f"Error creating ML model: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/ml-model/{model_id}/train") +async def train_ml_model(model_id: str, training_data: List[Dict[str, Any]]): + """Train an ML model""" + try: + result = await ai_integration.train_ml_model(model_id, training_data) + return result + except Exception as e: + logger.error(f"Error training ML model: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/ai/ml-model/{model_id}/predict") +async def predict_with_ml_model(model_id: str, features: List[float]): + """Make prediction with ML model""" + try: + result = await ai_integration.predict_with_ml_model(model_id, features) + return result + except Exception as e: + logger.error(f"Error predicting with ML model: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/ai/statistics") +async def get_ai_statistics(): + """Get comprehensive AI/ML statistics""" + try: + result = await ai_integration.get_ai_statistics() + return result + except Exception as e: + logger.error(f"Error getting AI statistics: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/alerts.py b/apps/agent-coordinator/src/app/routers/alerts.py new file mode 100644 index 00000000..f96dcb1a --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/alerts.py @@ -0,0 +1,218 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Alerting endpoints +@router.get("/alerts") +async def get_alerts( + status: Optional[str] = None, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Get alerts with optional status filter""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + if status == "active": + alerts = alert_manager.get_active_alerts() + else: + alerts = alert_manager.get_alert_history() + + return { + "status": "success", + "alerts": alerts, + "total": len(alerts) + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting alerts: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/alerts/{alert_id}/resolve") +async def resolve_alert( + alert_id: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Resolve an alert""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = alert_manager.resolve_alert(alert_id) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error resolving alert: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/alerts/stats") +async def get_alert_stats(current_user: Dict[str, Any] = Depends(get_current_user)): + """Get alert statistics""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + stats = alert_manager.get_alert_stats() + + return { + "status": "success", + "stats": stats + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting alert stats: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/alerts/rules") +async def get_alert_rules(current_user: Dict[str, Any] = Depends(get_current_user)): + """Get alert rules""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + rules = [rule.to_dict() for rule in alert_manager.rules.values()] + + return { + "status": "success", + "rules": rules, + "total": len(rules) + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting alert rules: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# SLA monitoring endpoints +@router.get("/sla") +async def get_sla_status( + sla_id: Optional[str] = None, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Get SLA status""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + if sla_id: + sla_status = alert_manager.sla_monitor.get_sla_compliance(sla_id) + else: + sla_status = alert_manager.sla_monitor.get_all_sla_status() + + return { + "status": "success", + "sla": sla_status + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting SLA status: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/sla/{sla_id}/record") +async def record_sla_metric( + sla_id: str, + value: float, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Record SLA metric""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + alert_manager.sla_monitor.record_metric(sla_id, value) + + return { + "status": "success", + "message": f"SLA metric recorded for {sla_id}", + "value": value, + "timestamp": datetime.utcnow().isoformat() + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error recording SLA metric: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# System status endpoint with monitoring +@router.get("/system/status") +async def get_system_status(current_user: Dict[str, Any] = Depends(get_current_user)): + """Get comprehensive system status""" + try: + if not permission_manager.has_permission(current_user["user_id"], Permission.SYSTEM_HEALTH): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + # Get various status information + performance = performance_monitor.get_performance_summary() + alerts = alert_manager.get_active_alerts() + sla_status = alert_manager.sla_monitor.get_all_sla_status() + + # Get system health + import psutil + memory = psutil.virtual_memory() + cpu = psutil.cpu_percent(interval=1) + + status = { + "overall": "healthy" if len(alerts) == 0 else "degraded", + "performance": performance, + "alerts": { + "active_count": len(alerts), + "critical_count": len([a for a in alerts if a.get("severity") == "critical"]), + "warning_count": len([a for a in alerts if a.get("severity") == "warning"]) + }, + "sla": { + "overall_compliance": sla_status.get("overall_compliance", 100.0), + "total_slas": sla_status.get("total_slas", 0) + }, + "system": { + "memory_usage": memory.percent, + "cpu_usage": cpu, + "uptime": performance["uptime_seconds"] + }, + "services": { + "agent_coordinator": "running", + "agent_registry": "running" if state.agent_registry else "stopped", + "load_balancer": "running" if state.load_balancer else "stopped", + "task_distributor": "running" if state.task_distributor else "stopped" + }, + "timestamp": datetime.utcnow().isoformat() + } + + return status + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting system status: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/auth.py b/apps/agent-coordinator/src/app/routers/auth.py new file mode 100644 index 00000000..388a8f99 --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/auth.py @@ -0,0 +1,196 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Authentication endpoints +@router.post("/auth/login") +async def login(login_data: Dict[str, str]): + """User login with username and password""" + try: + username = login_data.get("username") + password = login_data.get("password") + + if not username or not password: + raise HTTPException(status_code=422, detail="Username and password are required") + + # In a real implementation, verify credentials against database + # For demo, we'll create a simple user + import os + + demo_users = { + "admin": os.getenv("DEMO_ADMIN_PASSWORD", "admin123"), + "operator": os.getenv("DEMO_OPERATOR_PASSWORD", "operator123"), + "user": os.getenv("DEMO_USER_PASSWORD", "user123") + } + + if username == "admin" and password == demo_users["admin"]: + user_id = "admin_001" + role = Role.ADMIN + elif username == "operator" and password == demo_users["operator"]: + user_id = "operator_001" + role = Role.OPERATOR + elif username == "user" and password == demo_users["user"]: + user_id = "user_001" + role = Role.USER + else: + raise HTTPException(status_code=401, detail="Invalid credentials") + + # Assign role to user + permission_manager.assign_role(user_id, role) + + # Generate JWT token + token_result = jwt_handler.generate_token({ + "user_id": user_id, + "username": username, + "role": role.value, + "permissions": [perm.value for perm in permission_manager.user_permissions.get(user_id, set())] + }) + + # Generate refresh token + refresh_result = jwt_handler.generate_refresh_token({ + "user_id": user_id, + "username": username, + "role": role.value + }) + + return { + "status": "success", + "user_id": user_id, + "username": username, + "role": role.value, + "access_token": token_result["token"], + "refresh_token": refresh_result["refresh_token"], + "expires_at": token_result["expires_at"], + "token_type": token_result["token_type"] + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error during login: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/auth/refresh") +async def refresh_token(refresh_data: Dict[str, str]): + """Refresh access token using refresh token""" + try: + refresh_token = refresh_data.get("refresh_token") + + if not refresh_token: + raise HTTPException(status_code=422, detail="Refresh token is required") + + result = jwt_handler.refresh_access_token(refresh_token) + + if result["status"] == "error": + raise HTTPException(status_code=401, detail=result["message"]) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error refreshing token: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/auth/validate") +async def validate_token(validate_data: Dict[str, str]): + """Validate JWT token""" + try: + token = validate_data.get("token") + + if not token: + raise HTTPException(status_code=422, detail="Token is required") + + result = jwt_handler.validate_token(token) + + if not result["valid"]: + raise HTTPException(status_code=401, detail=result["message"]) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error validating token: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/auth/api-key/generate") +async def generate_api_key( + user_id: str, + permissions: List[str] = None, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Generate API key for user""" + try: + # Check if user has permission to generate API keys + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = api_key_manager.generate_api_key(user_id, permissions) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error generating API key: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/auth/api-key/validate") +async def validate_api_key(api_key: str): + """Validate API key""" + try: + result = api_key_manager.validate_api_key(api_key) + + if not result["valid"]: + raise HTTPException(status_code=401, detail="Invalid API key") + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error validating API key: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.delete("/auth/api-key/{api_key}") +async def revoke_api_key( + api_key: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Revoke API key""" + try: + # Check if user has permission to manage API keys + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_MANAGE): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = api_key_manager.revoke_api_key(api_key) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error revoking API key: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/consensus.py b/apps/agent-coordinator/src/app/routers/consensus.py new file mode 100644 index 00000000..b26e99da --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/consensus.py @@ -0,0 +1,133 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Distributed consensus endpoints +@router.post("/consensus/node/register") +async def register_consensus_node(node_data: Dict[str, Any]): + """Register a node in the consensus network""" + try: + result = await distributed_consensus.register_node(node_data) + return result + except Exception as e: + logger.error(f"Error registering consensus node: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/consensus/proposal/create") +async def create_consensus_proposal(proposal_data: Dict[str, Any]): + """Create a new consensus proposal""" + try: + result = await distributed_consensus.create_proposal(proposal_data) + return result + except Exception as e: + logger.error(f"Error creating consensus proposal: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/consensus/proposal/{proposal_id}/vote") +async def cast_consensus_vote(proposal_id: str, node_id: str, vote: bool): + """Cast a vote for a proposal""" + try: + result = await distributed_consensus.cast_vote(proposal_id, node_id, vote) + return result + except Exception as e: + logger.error(f"Error casting consensus vote: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/consensus/proposal/{proposal_id}") +async def get_proposal_status(proposal_id: str): + """Get proposal status""" + try: + result = await distributed_consensus.get_proposal_status(proposal_id) + return result + except Exception as e: + logger.error(f"Error getting proposal status: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.put("/consensus/algorithm") +async def set_consensus_algorithm(algorithm: str = Query(..., description="Consensus algorithm")): + """Set the consensus algorithm""" + try: + result = await distributed_consensus.set_consensus_algorithm(algorithm) + return result + except Exception as e: + logger.error(f"Error setting consensus algorithm: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/consensus/statistics") +async def get_consensus_statistics(): + """Get consensus statistics""" + try: + result = await distributed_consensus.get_consensus_statistics() + return result + except Exception as e: + logger.error(f"Error getting consensus statistics: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.put("/consensus/node/{node_id}/status") +async def update_node_status(node_id: str, is_active: bool): + """Update node status""" + try: + result = await distributed_consensus.update_node_status(node_id, is_active) + return result + except Exception as e: + logger.error(f"Error updating node status: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Advanced features status endpoint +@router.get("/advanced-features/status") +async def get_advanced_features_status(): + """Get status of all advanced features""" + try: + learning_stats = await learning_system.get_learning_statistics() + ai_stats = await ai_integration.get_ai_statistics() + consensus_stats = await distributed_consensus.get_consensus_statistics() + + return { + "status": "success", + "timestamp": datetime.utcnow().isoformat(), + "features": { + "realtime_learning": { + "status": "active", + "experiences": learning_stats.get("total_experiences", 0), + "learning_rate": learning_stats.get("learning_rate", 0.01), + "models": learning_stats.get("models_count", 0) + }, + "advanced_ai": { + "status": "active", + "models": ai_stats.get("total_models", 0), + "neural_networks": ai_stats.get("total_neural_networks", 0), + "predictions": ai_stats.get("total_predictions", 0) + }, + "distributed_consensus": { + "status": "active", + "nodes": consensus_stats.get("active_nodes", 0), + "proposals": consensus_stats.get("total_proposals", 0), + "success_rate": consensus_stats.get("success_rate", 0.0), + "algorithm": consensus_stats.get("current_algorithm", "majority_vote") + } + } + } + except Exception as e: + logger.error(f"Error getting advanced features status: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/health.py b/apps/agent-coordinator/src/app/routers/health.py new file mode 100644 index 00000000..db33de9a --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/health.py @@ -0,0 +1,57 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Health check endpoint +@router.get("/health") +async def health_check(): + """Health check endpoint""" + return { + "status": "healthy", + "service": "agent-coordinator", + "timestamp": datetime.utcnow().isoformat(), + "version": "1.0.0" + } + +# Root endpoint +@router.get("/") +async def root(): + """Root endpoint with service information""" + return { + "service": "AITBC Agent Coordinator", + "description": "Advanced multi-agent coordination and management system", + "version": "1.0.0", + "endpoints": [ + "/health", + "/agents/register", + "/agents/discover", + "/agents/{agent_id}", + "/agents/{agent_id}/status", + "/tasks/submit", + "/tasks/status", + "/messages/send", + "/load-balancer/stats", + "/registry/stats" + ] + } diff --git a/apps/agent-coordinator/src/app/routers/messages.py b/apps/agent-coordinator/src/app/routers/messages.py new file mode 100644 index 00000000..d51fc819 --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/messages.py @@ -0,0 +1,185 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Send message +@router.post("/messages/send") +async def send_message(request: MessageRequest): + """Send message to agent""" + try: + if not state.communication_manager: + raise HTTPException(status_code=503, detail="Communication manager not available") + + from ..protocols.communication import AgentMessage, Priority + + # Convert message type + try: + message_type = MessageType(request.message_type) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid message type: {request.message_type}") + + # Convert priority + try: + priority = Priority(request.priority.lower()) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid priority: {request.priority}") + + # Create message + message = AgentMessage( + sender_id="agent-coordinator", + receiver_id=request.receiver_id, + message_type=message_type, + priority=priority, + payload=request.payload + ) + + # Send message + success = await state.communication_manager.send_message("hierarchical", message) + + if success: + return { + "status": "success", + "message": "Message sent successfully", + "message_id": message.id, + "receiver_id": request.receiver_id, + "sent_at": datetime.utcnow().isoformat() + } + else: + raise HTTPException(status_code=500, detail="Failed to send message") + + except Exception as e: + logger.error(f"Error sending message: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Load balancer statistics +@router.get("/load-balancer/stats") +async def get_load_balancer_stats(): + """Get load balancer statistics""" + try: + if not state.load_balancer: + raise HTTPException(status_code=503, detail="Load balancer not available") + + stats = state.load_balancer.get_load_balancing_stats() + + return { + "status": "success", + "stats": stats, + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error getting load balancer stats: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Registry statistics +@router.get("/registry/stats") +async def get_registry_stats(): + """Get agent registry statistics""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + stats = await state.agent_registry.get_registry_stats() + + return { + "status": "success", + "stats": stats, + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error getting registry stats: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Get agents by service +@router.get("/agents/service/{service}") +async def get_agents_by_service(service: str): + """Get agents that provide a specific service""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + agents = await state.agent_registry.get_agents_by_service(service) + + return { + "status": "success", + "service": service, + "agents": [agent.to_dict() for agent in agents], + "count": len(agents), + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error getting agents by service: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Get agents by capability +@router.get("/agents/capability/{capability}") +async def get_agents_by_capability(capability: str): + """Get agents that have a specific capability""" + try: + if not state.agent_registry: + raise HTTPException(status_code=503, detail="Agent registry not available") + + agents = await state.agent_registry.get_agents_by_capability(capability) + + return { + "status": "success", + "capability": capability, + "agents": [agent.to_dict() for agent in agents], + "count": len(agents), + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error getting agents by capability: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Set load balancing strategy +@router.put("/load-balancer/strategy") +async def set_load_balancing_strategy(strategy: str = Query(..., description="Load balancing strategy")): + """Set load balancing strategy""" + try: + if not state.load_balancer: + raise HTTPException(status_code=503, detail="Load balancer not available") + + try: + load_balancing_strategy = LoadBalancingStrategy(strategy.lower()) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid strategy: {strategy}") + + state.load_balancer.set_strategy(load_balancing_strategy) + + return { + "status": "success", + "message": f"Load balancing strategy set to {strategy}", + "strategy": strategy, + "updated_at": datetime.utcnow().isoformat() + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error setting load balancing strategy: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/monitoring.py b/apps/agent-coordinator/src/app/routers/monitoring.py new file mode 100644 index 00000000..8cce7f6e --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/monitoring.py @@ -0,0 +1,129 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Monitoring and metrics endpoints +@router.get("/metrics") +async def get_prometheus_metrics(): + """Get metrics in Prometheus format""" + try: + metrics = metrics_registry.get_all_metrics() + + # Convert to Prometheus text format + prometheus_output = [] + + for name, metric_data in metrics.items(): + prometheus_output.append(f"# HELP {name} {metric_data['description']}") + prometheus_output.append(f"# TYPE {name} {metric_data['type']}") + + if metric_data['type'] == 'counter': + for labels, value in metric_data['values'].items(): + if labels != '_default': + prometheus_output.append(f"{name}{{{labels}}} {value}") + else: + prometheus_output.append(f"{name} {value}") + + elif metric_data['type'] == 'gauge': + for labels, value in metric_data['values'].items(): + if labels != '_default': + prometheus_output.append(f"{name}{{{labels}}} {value}") + else: + prometheus_output.append(f"{name} {value}") + + elif metric_data['type'] == 'histogram': + for key, count in metric_data['counts'].items(): + prometheus_output.append(f"{name}_count{{{key}}} {count}") + for key, sum_val in metric_data['sums'].items(): + prometheus_output.append(f"{name}_sum{{{key}}} {sum_val}") + + return Response( + content="\n".join(prometheus_output), + media_type="text/plain" + ) + + except Exception as e: + logger.error(f"Error getting metrics: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/metrics/summary") +async def get_metrics_summary(): + """Get metrics summary for dashboard""" + try: + summary = performance_monitor.get_performance_summary() + + # Add additional system metrics + system_metrics = { + "total_agents": len(state.agent_registry.agents) if state.agent_registry else 0, + "active_agents": len([a for a in state.agent_registry.agents.values() if getattr(a, 'is_active', True)]) if state.agent_registry else 0, + "total_tasks": len(state.task_distributor.task_queue._queue) if state.task_distributor and hasattr(state.task_distributor, 'task_queue') else 0, + "load_balancer_strategy": state.load_balancer.strategy.value if state.load_balancer else "unknown" + } + + return { + "status": "success", + "performance": summary, + "system": system_metrics, + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error getting metrics summary: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/metrics/health") +async def get_health_metrics(): + """Get health metrics for monitoring""" + try: + # Get system health metrics + import psutil + + memory = psutil.virtual_memory() + cpu = psutil.cpu_percent(interval=1) + + # Update performance monitor with system metrics + performance_monitor.update_system_metrics(memory.used, cpu) + + health_metrics = { + "memory": { + "total": memory.total, + "available": memory.available, + "used": memory.used, + "percentage": memory.percent + }, + "cpu": { + "percentage": cpu, + "count": psutil.cpu_count() + }, + "uptime": performance_monitor.get_performance_summary()["uptime_seconds"], + "timestamp": datetime.utcnow().isoformat() + } + + return { + "status": "success", + "health": health_metrics + } + + except Exception as e: + logger.error(f"Error getting health metrics: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/tasks.py b/apps/agent-coordinator/src/app/routers/tasks.py new file mode 100644 index 00000000..e7d71f2a --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/tasks.py @@ -0,0 +1,80 @@ +from datetime import datetime +import uuid +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# Submit task +@router.post("/tasks/submit") +async def submit_task(request: TaskSubmission, background_tasks: BackgroundTasks): + """Submit a task for distribution""" + try: + if not state.task_distributor: + raise HTTPException(status_code=503, detail="Task distributor not available") + + # Convert priority string to enum + try: + priority = TaskPriority(request.priority.lower()) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid priority: {request.priority}") + + # Submit task + await state.task_distributor.submit_task( + request.task_data, + priority, + request.requirements + ) + + return { + "status": "success", + "message": "Task submitted successfully", + "task_id": request.task_data.get("task_id", str(uuid.uuid4())), + "priority": request.priority, + "submitted_at": datetime.utcnow().isoformat() + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error submitting task: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Get task status +@router.get("/tasks/status") +async def get_task_status(): + """Get task distribution statistics""" + try: + if not state.task_distributor: + raise HTTPException(status_code=503, detail="Task distributor not available") + + stats = state.task_distributor.get_distribution_stats() + + return { + "status": "success", + "stats": stats, + "timestamp": datetime.utcnow().isoformat() + } + + except Exception as e: + logger.error(f"Error getting task status: {e}") + raise HTTPException(status_code=500, detail=str(e)) diff --git a/apps/agent-coordinator/src/app/routers/users.py b/apps/agent-coordinator/src/app/routers/users.py new file mode 100644 index 00000000..df51c51a --- /dev/null +++ b/apps/agent-coordinator/src/app/routers/users.py @@ -0,0 +1,244 @@ +from datetime import datetime +from typing import Any, Dict, List, Optional + +from aitbc import get_logger +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Response +from fastapi.responses import JSONResponse + +from .. import state +from ..auth.jwt_handler import api_key_manager, jwt_handler +from ..auth.middleware import get_current_user, require_role +from ..auth.permissions import Permission, Role, permission_manager +from ..ai.advanced_ai import ai_integration +from ..ai.realtime_learning import learning_system +from ..consensus.distributed_consensus import distributed_consensus +from ..models import AgentRegistrationRequest, AgentStatusUpdate, MessageRequest, TaskSubmission +from ..monitoring.alerting import alert_manager +from ..monitoring.prometheus_metrics import metrics_registry, performance_monitor +from ..protocols.communication import MessageType, create_protocol +from ..protocols.message_types import create_task_message +from ..routing.agent_discovery import create_agent_info +from ..routing.load_balancer import LoadBalancingStrategy, TaskPriority + +logger = get_logger(__name__) +router = APIRouter() + +# User management endpoints +@router.post("/users/{user_id}/role") +async def assign_user_role( + user_id: str, + role: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Assign role to user""" + try: + # Check if user has permission to manage roles + if not permission_manager.has_permission(current_user["user_id"], Permission.USER_MANAGE_ROLES): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + try: + role_enum = Role(role.lower()) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid role: {role}") + + result = permission_manager.assign_role(user_id, role_enum) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error assigning user role: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/users/{user_id}/role") +async def get_user_role( + user_id: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Get user's role""" + try: + # Check if user has permission to view users + if not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = permission_manager.get_user_role(user_id) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting user role: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/users/{user_id}/permissions") +async def get_user_permissions( + user_id: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Get user's permissions""" + try: + # Users can view their own permissions, admins can view any + if user_id != current_user["user_id"] and not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = permission_manager.get_user_permissions(user_id) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting user permissions: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/users/{user_id}/permissions/grant") +async def grant_user_permission( + user_id: str, + permission: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Grant custom permission to user""" + try: + # Check if user has permission to manage permissions + if not permission_manager.has_permission(current_user["user_id"], Permission.USER_MANAGE_ROLES): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + try: + permission_enum = Permission(permission) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid permission: {permission}") + + result = permission_manager.grant_custom_permission(user_id, permission_enum) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error granting user permission: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.delete("/users/{user_id}/permissions/{permission}") +async def revoke_user_permission( + user_id: str, + permission: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Revoke custom permission from user""" + try: + # Check if user has permission to manage permissions + if not permission_manager.has_permission(current_user["user_id"], Permission.USER_MANAGE_ROLES): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + try: + permission_enum = Permission(permission) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid permission: {permission}") + + result = permission_manager.revoke_custom_permission(user_id, permission_enum) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error revoking user permission: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Role and permission management endpoints +@router.get("/roles") +async def list_all_roles(current_user: Dict[str, Any] = Depends(get_current_user)): + """List all available roles and their permissions""" + try: + # Check if user has permission to view roles + if not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = permission_manager.list_all_roles() + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error listing roles: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/roles/{role}") +async def get_role_permissions( + role: str, + current_user: Dict[str, Any] = Depends(get_current_user) +): + """Get all permissions for a specific role""" + try: + # Check if user has permission to view roles + if not permission_manager.has_permission(current_user["user_id"], Permission.USER_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + try: + role_enum = Role(role.lower()) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid role: {role}") + + result = permission_manager.get_role_permissions(role_enum) + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting role permissions: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +@router.get("/auth/stats") +async def get_permission_stats(current_user: Dict[str, Any] = Depends(get_current_user)): + """Get statistics about permissions and users""" + try: + # Check if user has permission to view security stats + if not permission_manager.has_permission(current_user["user_id"], Permission.SECURITY_VIEW): + raise HTTPException(status_code=403, detail="Insufficient permissions") + + result = permission_manager.get_permission_stats() + + return result + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error getting permission stats: {e}") + raise HTTPException(status_code=500, detail=str(e)) + +# Protected endpoint example +@router.get("/protected/admin") +@require_role([Role.ADMIN]) +async def admin_only_endpoint(current_user: Dict[str, Any] = Depends(get_current_user)): + """Admin-only endpoint example""" + return { + "status": "success", + "message": "Welcome admin!", + "user": { + "user_id": current_user.get("user_id"), + "username": current_user.get("username"), + "role": str(current_user.get("role")), + "permissions": current_user.get("permissions", []), + "auth_type": current_user.get("auth_type") + } + } + +@router.get("/protected/operator") +@require_role([Role.ADMIN, Role.OPERATOR]) +async def operator_endpoint(current_user: Dict[str, Any] = Depends(get_current_user)): + """Operator and admin endpoint example""" + return { + "status": "success", + "message": "Welcome operator!", + "user": { + "user_id": current_user.get("user_id"), + "username": current_user.get("username"), + "role": str(current_user.get("role")), + "permissions": current_user.get("permissions", []), + "auth_type": current_user.get("auth_type") + } + } diff --git a/apps/agent-coordinator/src/app/state.py b/apps/agent-coordinator/src/app/state.py new file mode 100644 index 00000000..f8faf8f1 --- /dev/null +++ b/apps/agent-coordinator/src/app/state.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from typing import Optional + +from .protocols.communication import CommunicationManager +from .protocols.message_types import MessageProcessor +from .routing.agent_discovery import AgentDiscoveryService, AgentRegistry +from .routing.load_balancer import LoadBalancer, TaskDistributor + +agent_registry: Optional[AgentRegistry] = None +discovery_service: Optional[AgentDiscoveryService] = None +load_balancer: Optional[LoadBalancer] = None +task_distributor: Optional[TaskDistributor] = None +communication_manager: Optional[CommunicationManager] = None +message_processor: Optional[MessageProcessor] = None diff --git a/cli/parser_context.py b/cli/parser_context.py new file mode 100644 index 00000000..6ab4b267 --- /dev/null +++ b/cli/parser_context.py @@ -0,0 +1,28 @@ +"""Shared parser context for unified CLI command registration.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Callable, Mapping + + +@dataclass(slots=True) +class ParserContext: + default_rpc_url: str + default_coordinator_url: str + cli_version: str + first: Callable[..., Any] + read_password: Callable[..., Any] + output_format: Callable[..., Any] + render_mapping: Callable[..., Any] + read_blockchain_env: Callable[..., Any] + normalize_rpc_url: Callable[..., Any] + probe_rpc_node: Callable[..., Any] + get_network_snapshot: Callable[..., Any] + handlers: Mapping[str, Callable[..., Any]] + + def __getattr__(self, name: str): + try: + return self.handlers[name] + except KeyError as exc: + raise AttributeError(name) from exc diff --git a/cli/parsers/__init__.py b/cli/parsers/__init__.py new file mode 100644 index 00000000..fc6d0245 --- /dev/null +++ b/cli/parsers/__init__.py @@ -0,0 +1,19 @@ +"""Parser registration modules for the unified CLI.""" + +from . import ai, agent, blockchain, bridge, genesis, market, messaging, network, openclaw, pool_hub, resource, system, wallet, workflow + +def register_all(subparsers, ctx): + wallet.register(subparsers, ctx) + blockchain.register(subparsers, ctx) + messaging.register(subparsers, ctx) + network.register(subparsers, ctx) + market.register(subparsers, ctx) + ai.register(subparsers, ctx) + system.register(subparsers, ctx) + agent.register(subparsers, ctx) + openclaw.register(subparsers, ctx) + workflow.register(subparsers, ctx) + resource.register(subparsers, ctx) + genesis.register(subparsers, ctx) + pool_hub.register(subparsers, ctx) + bridge.register(subparsers, ctx) diff --git a/cli/parsers/agent.py b/cli/parsers/agent.py new file mode 100644 index 00000000..868bb38a --- /dev/null +++ b/cli/parsers/agent.py @@ -0,0 +1,51 @@ +"""Agent command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + agent_parser = subparsers.add_parser("agent", help="AI agent workflow orchestration") + agent_parser.set_defaults(handler=lambda parsed, parser=agent_parser: parser.print_help()) + agent_subparsers = agent_parser.add_subparsers(dest="agent_action") + + agent_create_parser = agent_subparsers.add_parser("create", help="Create an agent workflow") + agent_create_parser.add_argument("--name", required=True) + agent_create_parser.add_argument("--description") + agent_create_parser.add_argument("--workflow-file") + agent_create_parser.add_argument("--verification", choices=["basic", "full", "zero-knowledge"], default="basic") + agent_create_parser.add_argument("--max-execution-time", type=int, default=3600) + agent_create_parser.add_argument("--max-cost-budget", type=float, default=0.0) + agent_create_parser.set_defaults(handler=ctx.handle_agent_action) + + agent_execute_parser = agent_subparsers.add_parser("execute", help="Execute an agent workflow") + agent_execute_parser.add_argument("--name", required=True) + agent_execute_parser.add_argument("--input-data") + agent_execute_parser.add_argument("--wallet") + agent_execute_parser.add_argument("--priority", choices=["low", "medium", "high"], default="medium") + agent_execute_parser.set_defaults(handler=ctx.handle_agent_action) + + agent_status_parser = agent_subparsers.add_parser("status", help="Show agent status") + agent_status_parser.add_argument("--name") + agent_status_parser.add_argument("--execution-id") + agent_status_parser.set_defaults(handler=ctx.handle_agent_action) + + agent_list_parser = agent_subparsers.add_parser("list", help="List agents") + agent_list_parser.add_argument("--status", choices=["active", "completed", "failed"]) + agent_list_parser.set_defaults(handler=ctx.handle_agent_action) + + agent_message_parser = agent_subparsers.add_parser("message", help="Send message to agent") + agent_message_parser.add_argument("--agent", required=True) + agent_message_parser.add_argument("--message", required=True) + agent_message_parser.add_argument("--wallet", required=True) + agent_message_parser.add_argument("--password") + agent_message_parser.add_argument("--password-file") + agent_message_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + agent_message_parser.set_defaults(handler=ctx.handle_agent_action, agent_action="message") + + agent_messages_parser = agent_subparsers.add_parser("messages", help="List agent messages") + agent_messages_parser.add_argument("--agent", required=True) + agent_messages_parser.add_argument("--wallet") + agent_messages_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + agent_messages_parser.set_defaults(handler=ctx.handle_agent_action, agent_action="messages") diff --git a/cli/parsers/ai.py b/cli/parsers/ai.py new file mode 100644 index 00000000..a5cd4a9c --- /dev/null +++ b/cli/parsers/ai.py @@ -0,0 +1,77 @@ +"""AI command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + ai_parser = subparsers.add_parser("ai", help="AI job submission and inspection") + ai_parser.set_defaults(handler=lambda parsed, parser=ai_parser: parser.print_help()) + ai_subparsers = ai_parser.add_subparsers(dest="ai_action") + + ai_submit_parser = ai_subparsers.add_parser("submit", help="Submit an AI job") + ai_submit_parser.add_argument("wallet_name", nargs="?") + ai_submit_parser.add_argument("job_type_arg", nargs="?") + ai_submit_parser.add_argument("prompt_arg", nargs="?") + ai_submit_parser.add_argument("payment_arg", nargs="?") + ai_submit_parser.add_argument("--wallet") + ai_submit_parser.add_argument("--type", dest="job_type") + ai_submit_parser.add_argument("--prompt") + ai_submit_parser.add_argument("--payment", type=float) + ai_submit_parser.add_argument("--password") + ai_submit_parser.add_argument("--password-file") + ai_submit_parser.add_argument("--chain-id", help="Chain ID") + ai_submit_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + ai_submit_parser.set_defaults(handler=ctx.handle_ai_submit) + + ai_jobs_parser = ai_subparsers.add_parser("jobs", help="List AI jobs") + ai_jobs_parser.add_argument("--limit", type=int, default=10) + ai_jobs_parser.add_argument("--chain-id", help="Chain ID") + ai_jobs_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + ai_jobs_parser.set_defaults(handler=ctx.handle_ai_jobs) + + ai_status_parser = ai_subparsers.add_parser("status", help="Show AI job status") + ai_status_parser.add_argument("job_id_arg", nargs="?") + ai_status_parser.add_argument("--job-id", dest="job_id") + ai_status_parser.add_argument("--wallet") + ai_status_parser.add_argument("--chain-id", help="Chain ID") + ai_status_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + ai_status_parser.set_defaults(handler=ctx.handle_ai_job) + + ai_service_parser = ai_subparsers.add_parser("service", help="AI service management") + ai_service_subparsers = ai_service_parser.add_subparsers(dest="ai_service_action") + + ai_service_list_parser = ai_service_subparsers.add_parser("list", help="List available AI services") + ai_service_list_parser.set_defaults(handler=ctx.handle_ai_service_list) + + ai_service_status_parser = ai_service_subparsers.add_parser("status", help="Check AI service status") + ai_service_status_parser.add_argument("--name", help="Service name to check") + ai_service_status_parser.set_defaults(handler=ctx.handle_ai_service_status) + + ai_service_test_parser = ai_service_subparsers.add_parser("test", help="Test AI service endpoint") + ai_service_test_parser.add_argument("--name", help="Service name to test") + ai_service_test_parser.set_defaults(handler=ctx.handle_ai_service_test) + + ai_results_parser = ai_subparsers.add_parser("results", help="Show AI job results") + ai_results_parser.add_argument("job_id_arg", nargs="?") + ai_results_parser.add_argument("--job-id", dest="job_id") + ai_results_parser.add_argument("--wallet") + ai_results_parser.add_argument("--chain-id", help="Chain ID") + ai_results_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + ai_results_parser.set_defaults(handler=ctx.handle_ai_job) # Reuse job handler + + ai_cancel_parser = ai_subparsers.add_parser("cancel", help="Cancel AI job") + ai_cancel_parser.add_argument("job_id_arg", nargs="?") + ai_cancel_parser.add_argument("--job-id", dest="job_id") + ai_cancel_parser.add_argument("--wallet", required=True) + ai_cancel_parser.add_argument("--password") + ai_cancel_parser.add_argument("--password-file") + ai_cancel_parser.add_argument("--chain-id", help="Chain ID") + ai_cancel_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + ai_cancel_parser.set_defaults(handler=ctx.handle_ai_cancel) + + ai_stats_parser = ai_subparsers.add_parser("stats", help="AI service statistics") + ai_stats_parser.add_argument("--chain-id", help="Chain ID") + ai_stats_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + ai_stats_parser.set_defaults(handler=ctx.handle_ai_stats) diff --git a/cli/parsers/blockchain.py b/cli/parsers/blockchain.py new file mode 100644 index 00000000..7cc595c4 --- /dev/null +++ b/cli/parsers/blockchain.py @@ -0,0 +1,83 @@ +"""Blockchain command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + blockchain_parser = subparsers.add_parser("blockchain", help="Blockchain state and block inspection") + blockchain_parser.set_defaults(handler=ctx.handle_blockchain_info, rpc_url=ctx.default_rpc_url) + blockchain_subparsers = blockchain_parser.add_subparsers(dest="blockchain_action") + + blockchain_info_parser = blockchain_subparsers.add_parser("info", help="Show chain information") + blockchain_info_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_info_parser.set_defaults(handler=ctx.handle_blockchain_info) + + blockchain_height_parser = blockchain_subparsers.add_parser("height", help="Show current height") + blockchain_height_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_height_parser.set_defaults(handler=ctx.handle_blockchain_height) + + blockchain_block_parser = blockchain_subparsers.add_parser("block", help="Inspect a block") + blockchain_block_parser.add_argument("number", nargs="?", type=int) + blockchain_block_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_block_parser.set_defaults(handler=ctx.handle_blockchain_block) + + blockchain_init_parser = blockchain_subparsers.add_parser("init", help="Initialize blockchain with genesis block") + blockchain_init_parser.add_argument("--force", action="store_true", help="Force reinitialization") + blockchain_init_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_init_parser.set_defaults(handler=ctx.handle_blockchain_init) + + blockchain_genesis_parser = blockchain_subparsers.add_parser("genesis", help="Create or inspect genesis block") + blockchain_genesis_parser.add_argument("--create", action="store_true", help="Create new genesis block") + blockchain_genesis_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_genesis_parser.set_defaults(handler=ctx.handle_blockchain_genesis) + + blockchain_import_parser = blockchain_subparsers.add_parser("import", help="Import a block") + blockchain_import_parser.add_argument("--file", help="Block data file") + blockchain_import_parser.add_argument("--json", help="Block data as JSON string") + blockchain_import_parser.add_argument("--chain-id", help="Chain ID for the block") + blockchain_import_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_import_parser.set_defaults(handler=ctx.handle_blockchain_import) + + blockchain_export_parser = blockchain_subparsers.add_parser("export", help="Export full chain") + blockchain_export_parser.add_argument("--output", help="Output file") + blockchain_export_parser.add_argument("--chain-id", help="Chain ID to export") + blockchain_export_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_export_parser.set_defaults(handler=ctx.handle_blockchain_export) + + blockchain_import_chain_parser = blockchain_subparsers.add_parser("import-chain", help="Import chain state") + blockchain_import_chain_parser.add_argument("--file", required=True, help="Chain state file") + blockchain_import_chain_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_import_chain_parser.set_defaults(handler=ctx.handle_blockchain_import_chain) + + blockchain_blocks_range_parser = blockchain_subparsers.add_parser("blocks-range", help="Get blocks in height range") + blockchain_blocks_range_parser.add_argument("--start", type=int, help="Start height") + blockchain_blocks_range_parser.add_argument("--end", type=int, help="End height") + blockchain_blocks_range_parser.add_argument("--limit", type=int, default=10, help="Limit number of blocks") + blockchain_blocks_range_parser.add_argument("--chain-id", help="Chain ID") + blockchain_blocks_range_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_blocks_range_parser.set_defaults(handler=ctx.handle_blockchain_blocks_range) + + account_parser = subparsers.add_parser("account", help="Account information") + account_parser.set_defaults(handler=lambda parsed, parser=account_parser: parser.print_help()) + account_subparsers = account_parser.add_subparsers(dest="account_action") + + account_get_parser = account_subparsers.add_parser("get", help="Get account information") + account_get_parser.add_argument("--address", required=True, help="Account address") + account_get_parser.add_argument("--chain-id", help="Chain ID") + account_get_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + account_get_parser.set_defaults(handler=ctx.handle_account_get) + + blockchain_transactions_parser = blockchain_subparsers.add_parser("transactions", help="Query transactions") + blockchain_transactions_parser.add_argument("--address", help="Filter by address") + blockchain_transactions_parser.add_argument("--limit", type=int, default=10) + blockchain_transactions_parser.add_argument("--offset", type=int, default=0) + blockchain_transactions_parser.add_argument("--chain-id", help="Chain ID") + blockchain_transactions_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_transactions_parser.set_defaults(handler=ctx.handle_blockchain_transactions) + + blockchain_mempool_parser = blockchain_subparsers.add_parser("mempool", help="Get pending transactions") + blockchain_mempool_parser.add_argument("--chain-id", help="Chain ID") + blockchain_mempool_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + blockchain_mempool_parser.set_defaults(handler=ctx.handle_blockchain_mempool) diff --git a/cli/parsers/bridge.py b/cli/parsers/bridge.py new file mode 100644 index 00000000..ea6ad408 --- /dev/null +++ b/cli/parsers/bridge.py @@ -0,0 +1,31 @@ +"""Blockchain event bridge command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + bridge_parser = subparsers.add_parser("bridge", help="Blockchain event bridge management") + bridge_parser.set_defaults(handler=lambda parsed, parser=bridge_parser: parser.print_help()) + bridge_subparsers = bridge_parser.add_subparsers(dest="bridge_action") + + bridge_health_parser = bridge_subparsers.add_parser("health", help="Health check for blockchain event bridge service") + bridge_health_parser.add_argument("--test-mode", action="store_true") + bridge_health_parser.set_defaults(handler=ctx.handle_bridge_health) + + bridge_metrics_parser = bridge_subparsers.add_parser("metrics", help="Get Prometheus metrics from blockchain event bridge service") + bridge_metrics_parser.add_argument("--test-mode", action="store_true") + bridge_metrics_parser.set_defaults(handler=ctx.handle_bridge_metrics) + + bridge_status_parser = bridge_subparsers.add_parser("status", help="Get detailed status of blockchain event bridge service") + bridge_status_parser.add_argument("--test-mode", action="store_true") + bridge_status_parser.set_defaults(handler=ctx.handle_bridge_status) + + bridge_config_parser = bridge_subparsers.add_parser("config", help="Show current configuration of blockchain event bridge service") + bridge_config_parser.add_argument("--test-mode", action="store_true") + bridge_config_parser.set_defaults(handler=ctx.handle_bridge_config) + + bridge_restart_parser = bridge_subparsers.add_parser("restart", help="Restart blockchain event bridge service (via systemd)") + bridge_restart_parser.add_argument("--test-mode", action="store_true") + bridge_restart_parser.set_defaults(handler=ctx.handle_bridge_restart) diff --git a/cli/parsers/genesis.py b/cli/parsers/genesis.py new file mode 100644 index 00000000..9de908e3 --- /dev/null +++ b/cli/parsers/genesis.py @@ -0,0 +1,29 @@ +"""Genesis command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + genesis_parser = subparsers.add_parser("genesis", help="Genesis block and wallet generation") + genesis_parser.set_defaults(handler=lambda parsed, parser=genesis_parser: parser.print_help()) + genesis_subparsers = genesis_parser.add_subparsers(dest="genesis_action") + + genesis_init_parser = genesis_subparsers.add_parser("init", help="Initialize genesis block and wallet") + genesis_init_parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID for genesis") + genesis_init_parser.add_argument("--create-wallet", action="store_true", help="Create genesis wallet with secure random key") + genesis_init_parser.add_argument("--password", help="Wallet password (auto-generated if not provided)") + genesis_init_parser.add_argument("--proposer", help="Proposer address (defaults to genesis wallet)") + genesis_init_parser.add_argument("--force", action="store_true", help="Force overwrite existing genesis") + genesis_init_parser.add_argument("--register-service", action="store_true", help="Register genesis wallet with wallet service") + genesis_init_parser.add_argument("--service-url", default="http://localhost:8003", help="Wallet service URL") + genesis_init_parser.set_defaults(handler=ctx.handle_genesis_init) + + genesis_verify_parser = genesis_subparsers.add_parser("verify", help="Verify genesis block and wallet configuration") + genesis_verify_parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID to verify") + genesis_verify_parser.set_defaults(handler=ctx.handle_genesis_verify) + + genesis_info_parser = genesis_subparsers.add_parser("info", help="Show genesis block information") + genesis_info_parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID to show info for") + genesis_info_parser.set_defaults(handler=ctx.handle_genesis_info) diff --git a/cli/parsers/market.py b/cli/parsers/market.py new file mode 100644 index 00000000..72f83890 --- /dev/null +++ b/cli/parsers/market.py @@ -0,0 +1,97 @@ +"""Marketplace command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + market_parser = subparsers.add_parser("market", help="Marketplace listings and offers") + market_parser.set_defaults(handler=lambda parsed, parser=market_parser: parser.print_help()) + market_subparsers = market_parser.add_subparsers(dest="market_action") + + # GPU marketplace subcommands + market_gpu_parser = market_subparsers.add_parser("gpu", help="GPU marketplace operations") + market_gpu_parser.set_defaults(handler=lambda parsed, parser=market_gpu_parser: parser.print_help()) + market_gpu_subparsers = market_gpu_parser.add_subparsers(dest="gpu_action") + + market_gpu_register_parser = market_gpu_subparsers.add_parser("register", help="Register GPU on marketplace") + market_gpu_register_parser.add_argument("--name", help="GPU name/model") + market_gpu_register_parser.add_argument("--memory", type=int, help="GPU memory in GB") + market_gpu_register_parser.add_argument("--cuda-cores", type=int, help="Number of CUDA cores") + market_gpu_register_parser.add_argument("--compute-capability", help="Compute capability (e.g., 8.9)") + market_gpu_register_parser.add_argument("--price-per-hour", type=float, required=True, help="Price per hour in AIT") + market_gpu_register_parser.add_argument("--description", help="GPU description") + market_gpu_register_parser.add_argument("--miner-id", help="Miner ID") + market_gpu_register_parser.add_argument("--force", action="store_true", help="Force registration without hardware validation") + market_gpu_register_parser.add_argument("--coordinator-url", default=ctx.default_coordinator_url) + market_gpu_register_parser.set_defaults(handler=ctx.handle_market_gpu_register) + + market_gpu_list_parser = market_gpu_subparsers.add_parser("list", help="List available GPUs") + market_gpu_list_parser.add_argument("--available", action="store_true", help="Show only available GPUs") + market_gpu_list_parser.add_argument("--price-max", type=float, help="Maximum price per hour") + market_gpu_list_parser.add_argument("--region", help="Filter by region") + market_gpu_list_parser.add_argument("--model", help="Filter by GPU model") + market_gpu_list_parser.add_argument("--limit", type=int, default=100, help="Maximum number of results") + market_gpu_list_parser.add_argument("--coordinator-url", default=ctx.default_coordinator_url) + market_gpu_list_parser.set_defaults(handler=ctx.handle_market_gpu_list) + + market_list_parser = market_subparsers.add_parser("list", help="List marketplace items") + market_list_parser.add_argument("--chain-id", help="Chain ID") + market_list_parser.add_argument("--coordinator-url", default=ctx.default_coordinator_url) + market_list_parser.set_defaults(handler=ctx.handle_market_listings) + + market_create_parser = market_subparsers.add_parser("create", help="Create a marketplace listing") + market_create_parser.add_argument("--wallet", required=True) + market_create_parser.add_argument("--type", dest="item_type", required=True) + market_create_parser.add_argument("--price", type=float, required=True) + market_create_parser.add_argument("--description") + market_create_parser.add_argument("--password") + market_create_parser.add_argument("--password-file") + market_create_parser.add_argument("--chain-id", help="Chain ID") + market_create_parser.add_argument("--coordinator-url", default=ctx.default_coordinator_url) + market_create_parser.set_defaults(handler=ctx.handle_market_create) + + market_search_parser = market_subparsers.add_parser("search", help="Search marketplace items") + market_search_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + market_search_parser.set_defaults(handler=ctx.handle_market_listings) # Reuse listings for now + + market_mine_parser = market_subparsers.add_parser("my-listings", help="Show your marketplace listings") + market_mine_parser.add_argument("--wallet") + market_mine_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + market_mine_parser.set_defaults(handler=ctx.handle_market_listings) # Reuse listings for now + + market_get_parser = market_subparsers.add_parser("get", help="Get listing by ID") + market_get_parser.add_argument("--listing-id", required=True) + market_get_parser.add_argument("--chain-id", help="Chain ID") + market_get_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + market_get_parser.set_defaults(handler=ctx.handle_market_get) + + market_delete_parser = market_subparsers.add_parser("delete", help="Delete listing") + market_delete_parser.add_argument("--listing-id", required=True) + market_delete_parser.add_argument("--wallet", required=True) + market_delete_parser.add_argument("--password") + market_delete_parser.add_argument("--password-file") + market_delete_parser.add_argument("--chain-id", help="Chain ID") + market_delete_parser.add_argument("--coordinator-url", default=ctx.default_coordinator_url) + market_delete_parser.set_defaults(handler=ctx.handle_market_delete) + + market_buy_parser = market_subparsers.add_parser("buy", help="Buy from marketplace") + market_buy_parser.add_argument("--item", required=True) + market_buy_parser.add_argument("--wallet", required=True) + market_buy_parser.add_argument("--password") + market_buy_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + market_buy_parser.set_defaults(handler=ctx.handle_market_listings) # Placeholder + + market_sell_parser = market_subparsers.add_parser("sell", help="Sell on marketplace") + market_sell_parser.add_argument("--item", required=True) + market_sell_parser.add_argument("--price", type=float, required=True) + market_sell_parser.add_argument("--wallet", required=True) + market_sell_parser.add_argument("--password") + market_sell_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + market_sell_parser.set_defaults(handler=ctx.handle_market_create) # Reuse create + + market_orders_parser = market_subparsers.add_parser("orders", help="Show marketplace orders") + market_orders_parser.add_argument("--wallet") + market_orders_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + market_orders_parser.set_defaults(handler=ctx.handle_market_listings) # Reuse listings for now diff --git a/cli/parsers/messaging.py b/cli/parsers/messaging.py new file mode 100644 index 00000000..05f33785 --- /dev/null +++ b/cli/parsers/messaging.py @@ -0,0 +1,84 @@ +"""Messaging command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + messaging_parser = subparsers.add_parser("messaging", help="Messaging system and forum") + messaging_parser.set_defaults(handler=lambda parsed, parser=messaging_parser: parser.print_help()) + messaging_subparsers = messaging_parser.add_subparsers(dest="messaging_action") + + messaging_deploy_parser = messaging_subparsers.add_parser("deploy", help="Deploy messaging contract") + messaging_deploy_parser.add_argument("--chain-id", help="Chain ID") + messaging_deploy_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_deploy_parser.set_defaults(handler=ctx.handle_messaging_deploy) + + messaging_state_parser = messaging_subparsers.add_parser("state", help="Get contract state") + messaging_state_parser.add_argument("--chain-id", help="Chain ID") + messaging_state_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_state_parser.set_defaults(handler=ctx.handle_messaging_state) + + messaging_topics_parser = messaging_subparsers.add_parser("topics", help="List forum topics") + messaging_topics_parser.add_argument("--chain-id", help="Chain ID") + messaging_topics_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_topics_parser.set_defaults(handler=ctx.handle_messaging_topics) + + messaging_create_topic_parser = messaging_subparsers.add_parser("create-topic", help="Create forum topic") + messaging_create_topic_parser.add_argument("--title", required=True, help="Topic title") + messaging_create_topic_parser.add_argument("--content", required=True, help="Topic content") + messaging_create_topic_parser.add_argument("--wallet", help="Wallet address for authentication") + messaging_create_topic_parser.add_argument("--password") + messaging_create_topic_parser.add_argument("--password-file") + messaging_create_topic_parser.add_argument("--chain-id", help="Chain ID") + messaging_create_topic_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_create_topic_parser.set_defaults(handler=ctx.handle_messaging_create_topic) + + messaging_messages_parser = messaging_subparsers.add_parser("messages", help="Get topic messages") + messaging_messages_parser.add_argument("--topic-id", required=True, help="Topic ID") + messaging_messages_parser.add_argument("--chain-id", help="Chain ID") + messaging_messages_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_messages_parser.set_defaults(handler=ctx.handle_messaging_messages) + + messaging_post_parser = messaging_subparsers.add_parser("post", help="Post message") + messaging_post_parser.add_argument("--topic-id", required=True, help="Topic ID") + messaging_post_parser.add_argument("--content", required=True, help="Message content") + messaging_post_parser.add_argument("--wallet", help="Wallet address for authentication") + messaging_post_parser.add_argument("--password") + messaging_post_parser.add_argument("--password-file") + messaging_post_parser.add_argument("--chain-id", help="Chain ID") + messaging_post_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_post_parser.set_defaults(handler=ctx.handle_messaging_post) + + messaging_vote_parser = messaging_subparsers.add_parser("vote", help="Vote on message") + messaging_vote_parser.add_argument("--message-id", required=True, help="Message ID") + messaging_vote_parser.add_argument("--vote", required=True, help="Vote (up/down)") + messaging_vote_parser.add_argument("--wallet", help="Wallet address for authentication") + messaging_vote_parser.add_argument("--password") + messaging_vote_parser.add_argument("--password-file") + messaging_vote_parser.add_argument("--chain-id", help="Chain ID") + messaging_vote_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_vote_parser.set_defaults(handler=ctx.handle_messaging_vote) + + messaging_search_parser = messaging_subparsers.add_parser("search", help="Search messages") + messaging_search_parser.add_argument("--query", required=True, help="Search query") + messaging_search_parser.add_argument("--chain-id", help="Chain ID") + messaging_search_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_search_parser.set_defaults(handler=ctx.handle_messaging_search) + + messaging_reputation_parser = messaging_subparsers.add_parser("reputation", help="Get agent reputation") + messaging_reputation_parser.add_argument("--agent-id", required=True, help="Agent ID") + messaging_reputation_parser.add_argument("--chain-id", help="Chain ID") + messaging_reputation_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_reputation_parser.set_defaults(handler=ctx.handle_messaging_reputation) + + messaging_moderate_parser = messaging_subparsers.add_parser("moderate", help="Moderate message") + messaging_moderate_parser.add_argument("--message-id", required=True, help="Message ID") + messaging_moderate_parser.add_argument("--action", required=True, help="Action (approve/reject)") + messaging_moderate_parser.add_argument("--wallet", help="Wallet address for authentication") + messaging_moderate_parser.add_argument("--password") + messaging_moderate_parser.add_argument("--password-file") + messaging_moderate_parser.add_argument("--chain-id", help="Chain ID") + messaging_moderate_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + messaging_moderate_parser.set_defaults(handler=ctx.handle_messaging_moderate) diff --git a/cli/parsers/network.py b/cli/parsers/network.py new file mode 100644 index 00000000..a14dc13b --- /dev/null +++ b/cli/parsers/network.py @@ -0,0 +1,41 @@ +"""Network command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + network_parser = subparsers.add_parser("network", help="Peer connectivity and sync") + network_parser.set_defaults(handler=ctx.handle_network_status) + network_subparsers = network_parser.add_subparsers(dest="network_action") + + network_status_parser = network_subparsers.add_parser("status", help="Show network status") + network_status_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + network_status_parser.set_defaults(handler=ctx.handle_network_status) + + network_peers_parser = network_subparsers.add_parser("peers", help="List peers") + network_peers_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + network_peers_parser.set_defaults(handler=ctx.handle_network_peers) + + network_sync_parser = network_subparsers.add_parser("sync", help="Show sync status") + network_sync_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + network_sync_parser.set_defaults(handler=ctx.handle_network_sync) + + network_ping_parser = network_subparsers.add_parser("ping", help="Ping a node") + network_ping_parser.add_argument("node", nargs="?") + network_ping_parser.add_argument("--node", dest="node_opt", help=argparse.SUPPRESS) + network_ping_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + network_ping_parser.set_defaults(handler=ctx.handle_network_ping) + + network_propagate_parser = network_subparsers.add_parser("propagate", help="Propagate test data") + network_propagate_parser.add_argument("data", nargs="?") + network_propagate_parser.add_argument("--data", dest="data_opt", help=argparse.SUPPRESS) + network_propagate_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + network_propagate_parser.set_defaults(handler=ctx.handle_network_propagate) + + network_force_sync_parser = network_subparsers.add_parser("force-sync", help="Force reorg to specified peer") + network_force_sync_parser.add_argument("--peer", required=True, help="Peer to sync from") + network_force_sync_parser.add_argument("--chain-id", help="Chain ID") + network_force_sync_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + network_force_sync_parser.set_defaults(handler=ctx.handle_network_force_sync) diff --git a/cli/parsers/openclaw.py b/cli/parsers/openclaw.py new file mode 100644 index 00000000..1b89541a --- /dev/null +++ b/cli/parsers/openclaw.py @@ -0,0 +1,29 @@ +"""OpenClaw command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + openclaw_parser = subparsers.add_parser("openclaw", help="OpenClaw ecosystem operations") + openclaw_parser.set_defaults(handler=lambda parsed, parser=openclaw_parser: parser.print_help()) + openclaw_subparsers = openclaw_parser.add_subparsers(dest="openclaw_action") + + openclaw_deploy_parser = openclaw_subparsers.add_parser("deploy", help="Deploy an OpenClaw agent") + openclaw_deploy_parser.add_argument("--agent-file", required=True) + openclaw_deploy_parser.add_argument("--wallet", required=True) + openclaw_deploy_parser.add_argument("--environment", choices=["dev", "staging", "prod"], default="dev") + openclaw_deploy_parser.set_defaults(handler=ctx.handle_openclaw_action) + + openclaw_monitor_parser = openclaw_subparsers.add_parser("monitor", help="Monitor OpenClaw performance") + openclaw_monitor_parser.add_argument("--agent-id") + openclaw_monitor_parser.add_argument("--metrics", choices=["performance", "cost", "errors", "all"], default="all") + openclaw_monitor_parser.set_defaults(handler=ctx.handle_openclaw_action) + + openclaw_market_parser = openclaw_subparsers.add_parser("market", help="Manage OpenClaw marketplace activity") + openclaw_market_parser.add_argument("market_action", nargs="?", choices=["list", "publish", "purchase", "evaluate"]) + openclaw_market_parser.add_argument("--action", dest="market_action_opt", choices=["list", "publish", "purchase", "evaluate"], help=argparse.SUPPRESS) + openclaw_market_parser.add_argument("--agent-id") + openclaw_market_parser.add_argument("--price", type=float) + openclaw_market_parser.set_defaults(handler=ctx.handle_openclaw_action, openclaw_action="market") diff --git a/cli/parsers/pool_hub.py b/cli/parsers/pool_hub.py new file mode 100644 index 00000000..61459e12 --- /dev/null +++ b/cli/parsers/pool_hub.py @@ -0,0 +1,44 @@ +"""Pool hub command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + pool_hub_parser = subparsers.add_parser("pool-hub", help="Pool hub management for SLA monitoring and billing") + pool_hub_parser.set_defaults(handler=lambda parsed, parser=pool_hub_parser: parser.print_help()) + pool_hub_subparsers = pool_hub_parser.add_subparsers(dest="pool_hub_action") + + pool_hub_sla_metrics_parser = pool_hub_subparsers.add_parser("sla-metrics", help="Get SLA metrics for miner or all miners") + pool_hub_sla_metrics_parser.add_argument("miner_id", nargs="?") + pool_hub_sla_metrics_parser.add_argument("--test-mode", action="store_true") + pool_hub_sla_metrics_parser.set_defaults(handler=ctx.handle_pool_hub_sla_metrics) + + pool_hub_sla_violations_parser = pool_hub_subparsers.add_parser("sla-violations", help="Get SLA violations") + pool_hub_sla_violations_parser.add_argument("--test-mode", action="store_true") + pool_hub_sla_violations_parser.set_defaults(handler=ctx.handle_pool_hub_sla_violations) + + pool_hub_capacity_snapshots_parser = pool_hub_subparsers.add_parser("capacity-snapshots", help="Get capacity planning snapshots") + pool_hub_capacity_snapshots_parser.add_argument("--test-mode", action="store_true") + pool_hub_capacity_snapshots_parser.set_defaults(handler=ctx.handle_pool_hub_capacity_snapshots) + + pool_hub_capacity_forecast_parser = pool_hub_subparsers.add_parser("capacity-forecast", help="Get capacity forecast") + pool_hub_capacity_forecast_parser.add_argument("--test-mode", action="store_true") + pool_hub_capacity_forecast_parser.set_defaults(handler=ctx.handle_pool_hub_capacity_forecast) + + pool_hub_capacity_recommendations_parser = pool_hub_subparsers.add_parser("capacity-recommendations", help="Get scaling recommendations") + pool_hub_capacity_recommendations_parser.add_argument("--test-mode", action="store_true") + pool_hub_capacity_recommendations_parser.set_defaults(handler=ctx.handle_pool_hub_capacity_recommendations) + + pool_hub_billing_usage_parser = pool_hub_subparsers.add_parser("billing-usage", help="Get billing usage data") + pool_hub_billing_usage_parser.add_argument("--test-mode", action="store_true") + pool_hub_billing_usage_parser.set_defaults(handler=ctx.handle_pool_hub_billing_usage) + + pool_hub_billing_sync_parser = pool_hub_subparsers.add_parser("billing-sync", help="Trigger billing sync with coordinator-api") + pool_hub_billing_sync_parser.add_argument("--test-mode", action="store_true") + pool_hub_billing_sync_parser.set_defaults(handler=ctx.handle_pool_hub_billing_sync) + + pool_hub_collect_metrics_parser = pool_hub_subparsers.add_parser("collect-metrics", help="Trigger SLA metrics collection") + pool_hub_collect_metrics_parser.add_argument("--test-mode", action="store_true") + pool_hub_collect_metrics_parser.set_defaults(handler=ctx.handle_pool_hub_collect_metrics) diff --git a/cli/parsers/resource.py b/cli/parsers/resource.py new file mode 100644 index 00000000..1335ecc8 --- /dev/null +++ b/cli/parsers/resource.py @@ -0,0 +1,36 @@ +"""Resource command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + resource_parser = subparsers.add_parser("resource", help="Resource utilization and allocation") + resource_parser.set_defaults(handler=lambda parsed, parser=resource_parser: parser.print_help()) + resource_subparsers = resource_parser.add_subparsers(dest="resource_action") + + resource_status_parser = resource_subparsers.add_parser("status", help="Show resource status") + resource_status_parser.add_argument("--type", choices=["cpu", "memory", "storage", "network", "all"], default="all") + resource_status_parser.set_defaults(handler=ctx.handle_resource_action) + + resource_allocate_parser = resource_subparsers.add_parser("allocate", help="Allocate resources") + resource_allocate_parser.add_argument("--agent-id", required=True) + resource_allocate_parser.add_argument("--cpu", type=float) + resource_allocate_parser.add_argument("--memory", type=int) + resource_allocate_parser.add_argument("--duration", type=int) + resource_allocate_parser.set_defaults(handler=ctx.handle_resource_action) + + resource_optimize_parser = resource_subparsers.add_parser("optimize", help="Optimize resource usage") + resource_optimize_parser.add_argument("--agent-id") + resource_optimize_parser.add_argument("--target", choices=["cpu", "memory", "all"], default="all") + resource_optimize_parser.set_defaults(handler=ctx.handle_resource_action, resource_action="optimize") + + resource_benchmark_parser = resource_subparsers.add_parser("benchmark", help="Run resource benchmark") + resource_benchmark_parser.add_argument("--type", choices=["cpu", "memory", "io", "all"], default="all") + resource_benchmark_parser.set_defaults(handler=ctx.handle_resource_action, resource_action="benchmark") + + resource_monitor_parser = resource_subparsers.add_parser("monitor", help="Monitor resource utilization") + resource_monitor_parser.add_argument("--interval", type=int, default=5, help="Monitoring interval in seconds") + resource_monitor_parser.add_argument("--duration", type=int, default=60, help="Monitoring duration in seconds") + resource_monitor_parser.set_defaults(handler=ctx.handle_resource_action, resource_action="monitor") diff --git a/cli/parsers/system.py b/cli/parsers/system.py new file mode 100644 index 00000000..d0b7df4a --- /dev/null +++ b/cli/parsers/system.py @@ -0,0 +1,178 @@ +"""System, analytics, security, compliance, simulation, and cluster command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + mining_parser = subparsers.add_parser("mining", help="Mining lifecycle and rewards") + mining_parser.set_defaults(handler=ctx.handle_mining_action, mining_action="status") + mining_subparsers = mining_parser.add_subparsers(dest="mining_action") + + mining_status_parser = mining_subparsers.add_parser("status", help="Show mining status") + mining_status_parser.add_argument("--wallet") + mining_status_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + mining_status_parser.set_defaults(handler=ctx.handle_mining_action, mining_action="status") + + mining_start_parser = mining_subparsers.add_parser("start", help="Start mining") + mining_start_parser.add_argument("--wallet") + mining_start_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + mining_start_parser.set_defaults(handler=ctx.handle_mining_action, mining_action="start") + + mining_stop_parser = mining_subparsers.add_parser("stop", help="Stop mining") + mining_stop_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + mining_stop_parser.set_defaults(handler=ctx.handle_mining_action, mining_action="stop") + + mining_rewards_parser = mining_subparsers.add_parser("rewards", help="Show mining rewards") + mining_rewards_parser.add_argument("--wallet") + mining_rewards_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + mining_rewards_parser.set_defaults(handler=ctx.handle_mining_action, mining_action="rewards") + + analytics_parser = subparsers.add_parser("analytics", help="Blockchain analytics and statistics") + analytics_parser.set_defaults(handler=lambda parsed, parser=analytics_parser: parser.print_help()) + analytics_subparsers = analytics_parser.add_subparsers(dest="analytics_action") + + analytics_blocks_parser = analytics_subparsers.add_parser("blocks", help="Block analytics") + analytics_blocks_parser.add_argument("--limit", type=int, default=10) + analytics_blocks_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + analytics_blocks_parser.set_defaults(handler=ctx.handle_analytics, type="blocks") + + analytics_report_parser = analytics_subparsers.add_parser("report", help="Generate analytics report") + analytics_report_parser.add_argument("--type", choices=["performance", "transactions", "all"], default="all") + analytics_report_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + analytics_report_parser.set_defaults(handler=ctx.handle_analytics, type="report") + + analytics_metrics_parser = analytics_subparsers.add_parser("metrics", help="Show performance metrics") + analytics_metrics_parser.add_argument("--limit", type=int, default=10) + analytics_metrics_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + analytics_metrics_parser.set_defaults(handler=ctx.handle_analytics, type="metrics") + + analytics_export_parser = analytics_subparsers.add_parser("export", help="Export analytics data") + analytics_export_parser.add_argument("--format", choices=["json", "csv"], default="json") + analytics_export_parser.add_argument("--output") + analytics_export_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + analytics_export_parser.set_defaults(handler=ctx.handle_analytics, type="export") + + system_parser = subparsers.add_parser("system", help="System health and overview") + system_parser.set_defaults(handler=ctx.handle_system_status) + system_subparsers = system_parser.add_subparsers(dest="system_action") + + system_status_parser = system_subparsers.add_parser("status", help="Show system status") + system_status_parser.set_defaults(handler=ctx.handle_system_status) + + economics_parser = subparsers.add_parser("economics", help="Economic intelligence and modeling") + economics_parser.set_defaults(handler=lambda parsed, parser=economics_parser: parser.print_help()) + economics_subparsers = economics_parser.add_subparsers(dest="economics_action") + + economics_distributed_parser = economics_subparsers.add_parser("distributed", help="Distributed cost optimization") + economics_distributed_parser.add_argument("--cost-optimize", action="store_true") + economics_distributed_parser.set_defaults(handler=ctx.handle_economics_action) + + economics_market_parser = economics_subparsers.add_parser("market", help="Market analysis") + economics_market_parser.add_argument("--analyze", action="store_true") + economics_market_parser.set_defaults(handler=ctx.handle_economics_action) + + economics_trends_parser = economics_subparsers.add_parser("trends", help="Economic trends analysis") + economics_trends_parser.add_argument("--period") + economics_trends_parser.set_defaults(handler=ctx.handle_economics_action) + + economics_optimize_parser = economics_subparsers.add_parser("optimize", help="Optimize economic strategy") + economics_optimize_parser.add_argument("--target", choices=["revenue", "cost", "all"], default="all") + economics_optimize_parser.set_defaults(handler=ctx.handle_economics_action) + cluster_parser = subparsers.add_parser("cluster", help="Cluster management") + cluster_parser.set_defaults(handler=lambda parsed, parser=cluster_parser: parser.print_help()) + cluster_subparsers = cluster_parser.add_subparsers(dest="cluster_action") + + cluster_status_parser = cluster_subparsers.add_parser("status", help="Show cluster status") + cluster_status_parser.add_argument("--nodes", nargs="*", default=["aitbc", "aitbc1"]) + cluster_status_parser.set_defaults(handler=ctx.handle_network_status) + + cluster_sync_parser = cluster_subparsers.add_parser("sync", help="Sync cluster nodes") + cluster_sync_parser.add_argument("--all", action="store_true") + cluster_sync_parser.set_defaults(handler=ctx.handle_cluster_action) + + cluster_balance_parser = cluster_subparsers.add_parser("balance", help="Balance workload across nodes") + cluster_balance_parser.add_argument("--workload", action="store_true") + cluster_balance_parser.set_defaults(handler=ctx.handle_cluster_action) + + performance_parser = subparsers.add_parser("performance", help="Performance optimization") + performance_parser.set_defaults(handler=lambda parsed, parser=performance_parser: parser.print_help()) + performance_subparsers = performance_parser.add_subparsers(dest="performance_action") + + performance_benchmark_parser = performance_subparsers.add_parser("benchmark", help="Run performance benchmark") + performance_benchmark_parser.add_argument("--suite", choices=["comprehensive", "quick", "custom"], default="comprehensive") + performance_benchmark_parser.set_defaults(handler=ctx.handle_performance_action) + + performance_optimize_parser = performance_subparsers.add_parser("optimize", help="Optimize performance") + performance_optimize_parser.add_argument("--target", choices=["latency", "throughput", "all"], default="all") + performance_optimize_parser.set_defaults(handler=ctx.handle_performance_action) + + performance_tune_parser = performance_subparsers.add_parser("tune", help="Tune system parameters") + performance_tune_parser.add_argument("--parameters", action="store_true") + performance_tune_parser.add_argument("--aggressive", action="store_true") + performance_tune_parser.set_defaults(handler=ctx.handle_performance_action) + + security_parser = subparsers.add_parser("security", help="Security audit and scanning") + security_parser.set_defaults(handler=lambda parsed, parser=security_parser: parser.print_help()) + security_subparsers = security_parser.add_subparsers(dest="security_action") + + security_audit_parser = security_subparsers.add_parser("audit", help="Run security audit") + security_audit_parser.add_argument("--comprehensive", action="store_true") + security_audit_parser.set_defaults(handler=ctx.handle_security_action) + + security_scan_parser = security_subparsers.add_parser("scan", help="Scan for vulnerabilities") + security_scan_parser.add_argument("--vulnerabilities", action="store_true") + security_scan_parser.set_defaults(handler=ctx.handle_security_action) + + security_patch_parser = security_subparsers.add_parser("patch", help="Check for security patches") + security_patch_parser.add_argument("--critical", action="store_true") + security_patch_parser.set_defaults(handler=ctx.handle_security_action) + + compliance_parser = subparsers.add_parser("compliance", help="Compliance checking and reporting") + compliance_parser.set_defaults(handler=lambda parsed, parser=compliance_parser: parser.print_help()) + compliance_subparsers = compliance_parser.add_subparsers(dest="compliance_action") + + compliance_check_parser = compliance_subparsers.add_parser("check", help="Check compliance status") + compliance_check_parser.add_argument("--standard", choices=["gdpr", "hipaa", "soc2", "all"], default="gdpr") + compliance_check_parser.set_defaults(handler=ctx.handle_system_status) + + compliance_report_parser = compliance_subparsers.add_parser("report", help="Generate compliance report") + compliance_report_parser.add_argument("--format", choices=["detailed", "summary", "json"], default="detailed") + compliance_report_parser.set_defaults(handler=ctx.handle_system_status) + + simulate_parser = subparsers.add_parser("simulate", help="Simulation utilities") + simulate_parser.set_defaults(handler=lambda parsed, parser=simulate_parser: parser.print_help()) + simulate_subparsers = simulate_parser.add_subparsers(dest="simulate_command") + + simulate_blockchain_parser = simulate_subparsers.add_parser("blockchain", help="Simulate blockchain activity") + simulate_blockchain_parser.add_argument("--blocks", type=int, default=10) + simulate_blockchain_parser.add_argument("--transactions", type=int, default=50) + simulate_blockchain_parser.add_argument("--delay", type=float, default=1.0) + simulate_blockchain_parser.set_defaults(handler=ctx.handle_simulate_action) + + simulate_wallets_parser = simulate_subparsers.add_parser("wallets", help="Simulate wallet activity") + simulate_wallets_parser.add_argument("--wallets", type=int, default=5) + simulate_wallets_parser.add_argument("--balance", type=float, default=1000.0) + simulate_wallets_parser.add_argument("--transactions", type=int, default=20) + simulate_wallets_parser.add_argument("--amount-range", default="1.0-100.0") + simulate_wallets_parser.set_defaults(handler=ctx.handle_simulate_action) + + simulate_price_parser = simulate_subparsers.add_parser("price", help="Simulate price movement") + simulate_price_parser.add_argument("--price", type=float, default=100.0) + simulate_price_parser.add_argument("--volatility", type=float, default=0.05) + simulate_price_parser.add_argument("--timesteps", type=int, default=100) + simulate_price_parser.add_argument("--delay", type=float, default=0.1) + simulate_price_parser.set_defaults(handler=ctx.handle_simulate_action) + + simulate_network_parser = simulate_subparsers.add_parser("network", help="Simulate network topology") + simulate_network_parser.add_argument("--nodes", type=int, default=3) + simulate_network_parser.add_argument("--network-delay", type=float, default=0.1) + simulate_network_parser.add_argument("--failure-rate", type=float, default=0.05) + simulate_network_parser.set_defaults(handler=ctx.handle_simulate_action) + + simulate_ai_jobs_parser = simulate_subparsers.add_parser("ai-jobs", help="Simulate AI job traffic") + simulate_ai_jobs_parser.add_argument("--jobs", type=int, default=10) + simulate_ai_jobs_parser.add_argument("--models", default="text-generation") + simulate_ai_jobs_parser.add_argument("--duration-range", default="30-300") + simulate_ai_jobs_parser.set_defaults(handler=ctx.handle_simulate_action) diff --git a/cli/parsers/wallet.py b/cli/parsers/wallet.py new file mode 100644 index 00000000..5f4c8ba0 --- /dev/null +++ b/cli/parsers/wallet.py @@ -0,0 +1,102 @@ +"""Wallet command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + wallet_parser = subparsers.add_parser("wallet", help="Wallet lifecycle, balances, and transactions") + wallet_parser.set_defaults(handler=lambda parsed, parser=wallet_parser: parser.print_help()) + wallet_subparsers = wallet_parser.add_subparsers(dest="wallet_action") + + wallet_create_parser = wallet_subparsers.add_parser("create", help="Create a wallet") + wallet_create_parser.add_argument("wallet_name", nargs="?") + wallet_create_parser.add_argument("wallet_password", nargs="?") + wallet_create_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_create_parser.add_argument("--password") + wallet_create_parser.add_argument("--password-file") + wallet_create_parser.set_defaults(handler=ctx.handle_wallet_create) + + wallet_list_parser = wallet_subparsers.add_parser("list", help="List wallets") + wallet_list_parser.add_argument("--format", choices=["table", "json"], default="table") + wallet_list_parser.set_defaults(handler=ctx.handle_wallet_list) + + wallet_balance_parser = wallet_subparsers.add_parser("balance", help="Show wallet balance") + wallet_balance_parser.add_argument("wallet_name", nargs="?") + wallet_balance_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_balance_parser.add_argument("--all", action="store_true") + wallet_balance_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + wallet_balance_parser.add_argument("--chain-id", help="Chain ID for multichain operations (e.g., ait-mainnet, ait-devnet)") + wallet_balance_parser.set_defaults(handler=ctx.handle_wallet_balance) + + wallet_transactions_parser = wallet_subparsers.add_parser("transactions", help="Show wallet transactions") + wallet_transactions_parser.add_argument("wallet_name", nargs="?") + wallet_transactions_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_transactions_parser.add_argument("--limit", type=int, default=10) + wallet_transactions_parser.add_argument("--format", choices=["table", "json"], default="table") + wallet_transactions_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + wallet_transactions_parser.set_defaults(handler=ctx.handle_wallet_transactions) + + wallet_send_parser = wallet_subparsers.add_parser("send", help="Send AIT") + wallet_send_parser.add_argument("from_wallet_arg", nargs="?") + wallet_send_parser.add_argument("to_address_arg", nargs="?") + wallet_send_parser.add_argument("amount_arg", nargs="?") + wallet_send_parser.add_argument("wallet_password", nargs="?") + wallet_send_parser.add_argument("--from", dest="from_wallet", help=argparse.SUPPRESS) + wallet_send_parser.add_argument("--to", dest="to_address", help=argparse.SUPPRESS) + wallet_send_parser.add_argument("--amount", type=float) + wallet_send_parser.add_argument("--fee", type=float, default=10.0) + wallet_send_parser.add_argument("--password") + wallet_send_parser.add_argument("--password-file") + wallet_send_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + wallet_send_parser.set_defaults(handler=ctx.handle_wallet_send) + + wallet_import_parser = wallet_subparsers.add_parser("import", help="Import a wallet") + wallet_import_parser.add_argument("wallet_name", nargs="?") + wallet_import_parser.add_argument("private_key_arg", nargs="?") + wallet_import_parser.add_argument("wallet_password", nargs="?") + wallet_import_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_import_parser.add_argument("--private-key", dest="private_key_opt") + wallet_import_parser.add_argument("--password") + wallet_import_parser.add_argument("--password-file") + wallet_import_parser.set_defaults(handler=ctx.handle_wallet_import) + + wallet_export_parser = wallet_subparsers.add_parser("export", help="Export a wallet") + wallet_export_parser.add_argument("wallet_name", nargs="?") + wallet_export_parser.add_argument("wallet_password", nargs="?") + wallet_export_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_export_parser.add_argument("--password") + wallet_export_parser.add_argument("--password-file") + wallet_export_parser.set_defaults(handler=ctx.handle_wallet_export) + + wallet_delete_parser = wallet_subparsers.add_parser("delete", help="Delete a wallet") + wallet_delete_parser.add_argument("wallet_name", nargs="?") + wallet_delete_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_delete_parser.add_argument("--confirm", action="store_true") + wallet_delete_parser.set_defaults(handler=ctx.handle_wallet_delete) + + wallet_rename_parser = wallet_subparsers.add_parser("rename", help="Rename a wallet") + wallet_rename_parser.add_argument("old_name_arg", nargs="?") + wallet_rename_parser.add_argument("new_name_arg", nargs="?") + wallet_rename_parser.add_argument("--old", dest="old_name", help=argparse.SUPPRESS) + wallet_rename_parser.add_argument("--new", dest="new_name", help=argparse.SUPPRESS) + wallet_rename_parser.set_defaults(handler=ctx.handle_wallet_rename) + + wallet_backup_parser = wallet_subparsers.add_parser("backup", help="Backup a wallet") + wallet_backup_parser.add_argument("wallet_name", nargs="?") + wallet_backup_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_backup_parser.set_defaults(handler=ctx.handle_wallet_backup) + + wallet_sync_parser = wallet_subparsers.add_parser("sync", help="Sync wallets") + wallet_sync_parser.add_argument("wallet_name", nargs="?") + wallet_sync_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) + wallet_sync_parser.add_argument("--all", action="store_true") + wallet_sync_parser.set_defaults(handler=ctx.handle_wallet_sync) + + wallet_batch_parser = wallet_subparsers.add_parser("batch", help="Send multiple transactions") + wallet_batch_parser.add_argument("--file", required=True) + wallet_batch_parser.add_argument("--password") + wallet_batch_parser.add_argument("--password-file") + wallet_batch_parser.add_argument("--rpc-url", default=ctx.default_rpc_url) + wallet_batch_parser.set_defaults(handler=ctx.handle_wallet_batch) diff --git a/cli/parsers/workflow.py b/cli/parsers/workflow.py new file mode 100644 index 00000000..58fb6694 --- /dev/null +++ b/cli/parsers/workflow.py @@ -0,0 +1,34 @@ +"""Workflow command registration for the unified CLI.""" + +import argparse + +from parser_context import ParserContext + + +def register(subparsers: argparse._SubParsersAction, ctx: ParserContext) -> None: + workflow_parser = subparsers.add_parser("workflow", help="Workflow templates and execution") + workflow_parser.set_defaults(handler=lambda parsed, parser=workflow_parser: parser.print_help()) + workflow_subparsers = workflow_parser.add_subparsers(dest="workflow_action") + + workflow_create_parser = workflow_subparsers.add_parser("create", help="Create a workflow") + workflow_create_parser.add_argument("--name", required=True) + workflow_create_parser.add_argument("--template") + workflow_create_parser.add_argument("--config-file") + workflow_create_parser.set_defaults(handler=ctx.handle_workflow_action) + + workflow_run_parser = workflow_subparsers.add_parser("run", help="Run a workflow") + workflow_run_parser.add_argument("--name", required=True) + workflow_run_parser.add_argument("--params") + workflow_run_parser.add_argument("--async-exec", action="store_true") + workflow_run_parser.set_defaults(handler=ctx.handle_workflow_action) + + workflow_schedule_parser = workflow_subparsers.add_parser("schedule", help="Schedule a workflow") + workflow_schedule_parser.add_argument("--name", required=True) + workflow_schedule_parser.add_argument("--cron", required=True) + workflow_schedule_parser.add_argument("--params") + workflow_schedule_parser.set_defaults(handler=ctx.handle_workflow_action, workflow_action="schedule") + + workflow_monitor_parser = workflow_subparsers.add_parser("monitor", help="Monitor workflow execution") + workflow_monitor_parser.add_argument("--name") + workflow_monitor_parser.add_argument("--execution-id") + workflow_monitor_parser.set_defaults(handler=ctx.handle_workflow_action, workflow_action="monitor") diff --git a/cli/unified_cli.py b/cli/unified_cli.py index 90ecd4f0..a9b9b941 100755 --- a/cli/unified_cli.py +++ b/cli/unified_cli.py @@ -2,10 +2,13 @@ import argparse import json import os import sys +from pathlib import Path from urllib.parse import urlparse import requests +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + # Import command handlers from handlers import market as market_handlers from handlers import wallet as wallet_handlers @@ -17,6 +20,8 @@ from handlers import system as system_handlers from handlers import pool_hub as pool_hub_handlers from handlers import bridge as bridge_handlers from handlers import account as account_handlers +from parser_context import ParserContext +from parsers import register_all def run_cli(argv, core): @@ -511,6 +516,129 @@ def run_cli(argv, core): except Exception as e: print(f"❌ Error restarting blockchain event bridge service: {e}") + handlers = { + "handle_wallet_create": handle_wallet_create, + "handle_wallet_list": handle_wallet_list, + "handle_wallet_balance": handle_wallet_balance, + "handle_wallet_transactions": handle_wallet_transactions, + "handle_wallet_send": handle_wallet_send, + "handle_wallet_import": handle_wallet_import, + "handle_wallet_export": handle_wallet_export, + "handle_wallet_delete": handle_wallet_delete, + "handle_wallet_rename": handle_wallet_rename, + "handle_wallet_backup": handle_wallet_backup, + "handle_wallet_sync": handle_wallet_sync, + "handle_wallet_batch": handle_wallet_batch, + "handle_blockchain_info": handle_blockchain_info, + "handle_blockchain_height": handle_blockchain_height, + "handle_blockchain_block": handle_blockchain_block, + "handle_blockchain_init": handle_blockchain_init, + "handle_blockchain_genesis": handle_blockchain_genesis, + "handle_blockchain_import": handle_blockchain_import, + "handle_blockchain_export": handle_blockchain_export, + "handle_blockchain_import_chain": handle_blockchain_import_chain, + "handle_blockchain_blocks_range": handle_blockchain_blocks_range, + "handle_blockchain_transactions": handle_blockchain_transactions, + "handle_blockchain_mempool": handle_blockchain_mempool, + "handle_account_get": handle_account_get, + "handle_messaging_deploy": handle_messaging_deploy, + "handle_messaging_state": handle_messaging_state, + "handle_messaging_topics": handle_messaging_topics, + "handle_messaging_create_topic": handle_messaging_create_topic, + "handle_messaging_messages": handle_messaging_messages, + "handle_messaging_post": handle_messaging_post, + "handle_messaging_vote": handle_messaging_vote, + "handle_messaging_search": handle_messaging_search, + "handle_messaging_reputation": handle_messaging_reputation, + "handle_messaging_moderate": handle_messaging_moderate, + "handle_network_status": handle_network_status, + "handle_network_peers": handle_network_peers, + "handle_network_sync": handle_network_sync, + "handle_network_ping": handle_network_ping, + "handle_network_propagate": handle_network_propagate, + "handle_network_force_sync": handle_network_force_sync, + "handle_market_listings": handle_market_listings, + "handle_market_create": handle_market_create, + "handle_market_get": handle_market_get, + "handle_market_delete": handle_market_delete, + "handle_market_gpu_register": handle_market_gpu_register, + "handle_market_gpu_list": handle_market_gpu_list, + "handle_ai_submit": handle_ai_submit, + "handle_ai_jobs": handle_ai_jobs, + "handle_ai_job": handle_ai_job, + "handle_ai_cancel": handle_ai_cancel, + "handle_ai_stats": handle_ai_stats, + "handle_ai_service_list": handle_ai_service_list, + "handle_ai_service_status": handle_ai_service_status, + "handle_ai_service_test": handle_ai_service_test, + "handle_mining_action": handle_mining_action, + "handle_system_status": handle_system_status, + "handle_analytics": handle_analytics, + "handle_economics_action": handle_economics_action, + "handle_cluster_action": handle_cluster_action, + "handle_performance_action": handle_performance_action, + "handle_security_action": handle_security_action, + "handle_simulate_action": handle_simulate_action, + "handle_agent_action": handle_agent_action, + "handle_openclaw_action": handle_openclaw_action, + "handle_workflow_action": handle_workflow_action, + "handle_resource_action": handle_resource_action, + "handle_pool_hub_sla_metrics": handle_pool_hub_sla_metrics, + "handle_pool_hub_sla_violations": handle_pool_hub_sla_violations, + "handle_pool_hub_capacity_snapshots": handle_pool_hub_capacity_snapshots, + "handle_pool_hub_capacity_forecast": handle_pool_hub_capacity_forecast, + "handle_pool_hub_capacity_recommendations": handle_pool_hub_capacity_recommendations, + "handle_pool_hub_billing_usage": handle_pool_hub_billing_usage, + "handle_pool_hub_billing_sync": handle_pool_hub_billing_sync, + "handle_pool_hub_collect_metrics": handle_pool_hub_collect_metrics, + "handle_bridge_health": handle_bridge_health, + "handle_bridge_metrics": handle_bridge_metrics, + "handle_bridge_status": handle_bridge_status, + "handle_bridge_config": globals()["handle_bridge_config"], + "handle_bridge_restart": globals()["handle_bridge_restart"], + "handle_genesis_init": globals()["handle_genesis_init"], + "handle_genesis_verify": globals()["handle_genesis_verify"], + "handle_genesis_info": globals()["handle_genesis_info"], + } + + ctx = ParserContext( + default_rpc_url=default_rpc_url, + default_coordinator_url=default_coordinator_url, + cli_version=cli_version, + first=first, + read_password=read_password, + output_format=output_format, + render_mapping=render_mapping, + read_blockchain_env=read_blockchain_env, + normalize_rpc_url=normalize_rpc_url, + probe_rpc_node=probe_rpc_node, + get_network_snapshot=get_network_snapshot, + handlers=handlers, + ) + + parser = argparse.ArgumentParser( + description="AITBC CLI - Comprehensive Blockchain Management Tool", + epilog="Examples: aitbc wallet create demo secret | aitbc wallet balance demo | aitbc ai submit --wallet demo --type text-generation --prompt 'hello' --payment 1", + ) + parser.add_argument("--version", action="version", version=f"aitbc-cli {cli_version}") + parser.add_argument("--output", choices=["table", "json", "yaml"], default="table") + parser.add_argument("--verbose", action="store_true") + parser.add_argument("--debug", action="store_true") + subparsers = parser.add_subparsers(dest="command") + + register_all(subparsers, ctx) + + parsed_args = parser.parse_args(normalize_legacy_args(list(raw_args))) + if not getattr(parsed_args, "command", None): + parser.print_help() + return 0 + handler = getattr(parsed_args, "handler", None) + if handler is None: + parser.print_help() + return 0 + handler(parsed_args) + return 0 + def handle_genesis_init(args): """Initialize genesis block and wallet""" import subprocess @@ -661,842 +789,11 @@ def handle_bridge_config(args): def handle_bridge_restart(args): bridge_handlers.handle_bridge_restart(args) -def main(): - parser = argparse.ArgumentParser( - description="AITBC CLI - Comprehensive Blockchain Management Tool", - epilog="Examples: aitbc wallet create demo secret | aitbc wallet balance demo | aitbc ai submit --wallet demo --type text-generation --prompt 'hello' --payment 1", - ) - parser.add_argument("--version", action="version", version=f"aitbc-cli {cli_version}") - parser.add_argument("--output", choices=["table", "json", "yaml"], default="table") - parser.add_argument("--verbose", action="store_true") - parser.add_argument("--debug", action="store_true") - subparsers = parser.add_subparsers(dest="command") +def main(argv=None): + from aitbc_cli import main as cli_main - wallet_parser = subparsers.add_parser("wallet", help="Wallet lifecycle, balances, and transactions") - wallet_parser.set_defaults(handler=lambda parsed, parser=wallet_parser: parser.print_help()) - wallet_subparsers = wallet_parser.add_subparsers(dest="wallet_action") + return cli_main(argv) - wallet_create_parser = wallet_subparsers.add_parser("create", help="Create a wallet") - wallet_create_parser.add_argument("wallet_name", nargs="?") - wallet_create_parser.add_argument("wallet_password", nargs="?") - wallet_create_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_create_parser.add_argument("--password") - wallet_create_parser.add_argument("--password-file") - wallet_create_parser.set_defaults(handler=handle_wallet_create) - wallet_list_parser = wallet_subparsers.add_parser("list", help="List wallets") - wallet_list_parser.add_argument("--format", choices=["table", "json"], default="table") - wallet_list_parser.set_defaults(handler=handle_wallet_list) - - wallet_balance_parser = wallet_subparsers.add_parser("balance", help="Show wallet balance") - wallet_balance_parser.add_argument("wallet_name", nargs="?") - wallet_balance_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_balance_parser.add_argument("--all", action="store_true") - wallet_balance_parser.add_argument("--rpc-url", default=default_rpc_url) - wallet_balance_parser.add_argument("--chain-id", help="Chain ID for multichain operations (e.g., ait-mainnet, ait-devnet)") - wallet_balance_parser.set_defaults(handler=handle_wallet_balance) - - wallet_transactions_parser = wallet_subparsers.add_parser("transactions", help="Show wallet transactions") - wallet_transactions_parser.add_argument("wallet_name", nargs="?") - wallet_transactions_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_transactions_parser.add_argument("--limit", type=int, default=10) - wallet_transactions_parser.add_argument("--format", choices=["table", "json"], default="table") - wallet_transactions_parser.add_argument("--rpc-url", default=default_rpc_url) - wallet_transactions_parser.set_defaults(handler=handle_wallet_transactions) - - wallet_send_parser = wallet_subparsers.add_parser("send", help="Send AIT") - wallet_send_parser.add_argument("from_wallet_arg", nargs="?") - wallet_send_parser.add_argument("to_address_arg", nargs="?") - wallet_send_parser.add_argument("amount_arg", nargs="?") - wallet_send_parser.add_argument("wallet_password", nargs="?") - wallet_send_parser.add_argument("--from", dest="from_wallet", help=argparse.SUPPRESS) - wallet_send_parser.add_argument("--to", dest="to_address", help=argparse.SUPPRESS) - wallet_send_parser.add_argument("--amount", type=float) - wallet_send_parser.add_argument("--fee", type=float, default=10.0) - wallet_send_parser.add_argument("--password") - wallet_send_parser.add_argument("--password-file") - wallet_send_parser.add_argument("--rpc-url", default=default_rpc_url) - wallet_send_parser.set_defaults(handler=handle_wallet_send) - - wallet_import_parser = wallet_subparsers.add_parser("import", help="Import a wallet") - wallet_import_parser.add_argument("wallet_name", nargs="?") - wallet_import_parser.add_argument("private_key_arg", nargs="?") - wallet_import_parser.add_argument("wallet_password", nargs="?") - wallet_import_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_import_parser.add_argument("--private-key", dest="private_key_opt") - wallet_import_parser.add_argument("--password") - wallet_import_parser.add_argument("--password-file") - wallet_import_parser.set_defaults(handler=handle_wallet_import) - - wallet_export_parser = wallet_subparsers.add_parser("export", help="Export a wallet") - wallet_export_parser.add_argument("wallet_name", nargs="?") - wallet_export_parser.add_argument("wallet_password", nargs="?") - wallet_export_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_export_parser.add_argument("--password") - wallet_export_parser.add_argument("--password-file") - wallet_export_parser.set_defaults(handler=handle_wallet_export) - - wallet_delete_parser = wallet_subparsers.add_parser("delete", help="Delete a wallet") - wallet_delete_parser.add_argument("wallet_name", nargs="?") - wallet_delete_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_delete_parser.add_argument("--confirm", action="store_true") - wallet_delete_parser.set_defaults(handler=handle_wallet_delete) - - wallet_rename_parser = wallet_subparsers.add_parser("rename", help="Rename a wallet") - wallet_rename_parser.add_argument("old_name_arg", nargs="?") - wallet_rename_parser.add_argument("new_name_arg", nargs="?") - wallet_rename_parser.add_argument("--old", dest="old_name", help=argparse.SUPPRESS) - wallet_rename_parser.add_argument("--new", dest="new_name", help=argparse.SUPPRESS) - wallet_rename_parser.set_defaults(handler=handle_wallet_rename) - - wallet_backup_parser = wallet_subparsers.add_parser("backup", help="Backup a wallet") - wallet_backup_parser.add_argument("wallet_name", nargs="?") - wallet_backup_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_backup_parser.set_defaults(handler=handle_wallet_backup) - - wallet_sync_parser = wallet_subparsers.add_parser("sync", help="Sync wallets") - wallet_sync_parser.add_argument("wallet_name", nargs="?") - wallet_sync_parser.add_argument("--name", dest="wallet_name_opt", help=argparse.SUPPRESS) - wallet_sync_parser.add_argument("--all", action="store_true") - wallet_sync_parser.set_defaults(handler=handle_wallet_sync) - - wallet_batch_parser = wallet_subparsers.add_parser("batch", help="Send multiple transactions") - wallet_batch_parser.add_argument("--file", required=True) - wallet_batch_parser.add_argument("--password") - wallet_batch_parser.add_argument("--password-file") - wallet_batch_parser.add_argument("--rpc-url", default=default_rpc_url) - wallet_batch_parser.set_defaults(handler=handle_wallet_batch) - - blockchain_parser = subparsers.add_parser("blockchain", help="Blockchain state and block inspection") - blockchain_parser.set_defaults(handler=handle_blockchain_info, rpc_url=default_rpc_url) - blockchain_subparsers = blockchain_parser.add_subparsers(dest="blockchain_action") - - blockchain_info_parser = blockchain_subparsers.add_parser("info", help="Show chain information") - blockchain_info_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_info_parser.set_defaults(handler=handle_blockchain_info) - - blockchain_height_parser = blockchain_subparsers.add_parser("height", help="Show current height") - blockchain_height_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_height_parser.set_defaults(handler=handle_blockchain_height) - - blockchain_block_parser = blockchain_subparsers.add_parser("block", help="Inspect a block") - blockchain_block_parser.add_argument("number", nargs="?", type=int) - blockchain_block_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_block_parser.set_defaults(handler=handle_blockchain_block) - - blockchain_init_parser = blockchain_subparsers.add_parser("init", help="Initialize blockchain with genesis block") - blockchain_init_parser.add_argument("--force", action="store_true", help="Force reinitialization") - blockchain_init_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_init_parser.set_defaults(handler=handle_blockchain_init) - - blockchain_genesis_parser = blockchain_subparsers.add_parser("genesis", help="Create or inspect genesis block") - blockchain_genesis_parser.add_argument("--create", action="store_true", help="Create new genesis block") - blockchain_genesis_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_genesis_parser.set_defaults(handler=handle_blockchain_genesis) - - blockchain_import_parser = blockchain_subparsers.add_parser("import", help="Import a block") - blockchain_import_parser.add_argument("--file", help="Block data file") - blockchain_import_parser.add_argument("--json", help="Block data as JSON string") - blockchain_import_parser.add_argument("--chain-id", help="Chain ID for the block") - blockchain_import_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_import_parser.set_defaults(handler=handle_blockchain_import) - - blockchain_export_parser = blockchain_subparsers.add_parser("export", help="Export full chain") - blockchain_export_parser.add_argument("--output", help="Output file") - blockchain_export_parser.add_argument("--chain-id", help="Chain ID to export") - blockchain_export_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_export_parser.set_defaults(handler=handle_blockchain_export) - - blockchain_import_chain_parser = blockchain_subparsers.add_parser("import-chain", help="Import chain state") - blockchain_import_chain_parser.add_argument("--file", required=True, help="Chain state file") - blockchain_import_chain_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_import_chain_parser.set_defaults(handler=handle_blockchain_import_chain) - - blockchain_blocks_range_parser = blockchain_subparsers.add_parser("blocks-range", help="Get blocks in height range") - blockchain_blocks_range_parser.add_argument("--start", type=int, help="Start height") - blockchain_blocks_range_parser.add_argument("--end", type=int, help="End height") - blockchain_blocks_range_parser.add_argument("--limit", type=int, default=10, help="Limit number of blocks") - blockchain_blocks_range_parser.add_argument("--chain-id", help="Chain ID") - blockchain_blocks_range_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_blocks_range_parser.set_defaults(handler=handle_blockchain_blocks_range) - - account_parser = subparsers.add_parser("account", help="Account information") - account_parser.set_defaults(handler=lambda parsed, parser=account_parser: parser.print_help()) - account_subparsers = account_parser.add_subparsers(dest="account_action") - - account_get_parser = account_subparsers.add_parser("get", help="Get account information") - account_get_parser.add_argument("--address", required=True, help="Account address") - account_get_parser.add_argument("--chain-id", help="Chain ID") - account_get_parser.add_argument("--rpc-url", default=default_rpc_url) - account_get_parser.set_defaults(handler=handle_account_get) - - blockchain_transactions_parser = blockchain_subparsers.add_parser("transactions", help="Query transactions") - blockchain_transactions_parser.add_argument("--address", help="Filter by address") - blockchain_transactions_parser.add_argument("--limit", type=int, default=10) - blockchain_transactions_parser.add_argument("--offset", type=int, default=0) - blockchain_transactions_parser.add_argument("--chain-id", help="Chain ID") - blockchain_transactions_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_transactions_parser.set_defaults(handler=handle_blockchain_transactions) - - blockchain_mempool_parser = blockchain_subparsers.add_parser("mempool", help="Get pending transactions") - blockchain_mempool_parser.add_argument("--chain-id", help="Chain ID") - blockchain_mempool_parser.add_argument("--rpc-url", default=default_rpc_url) - blockchain_mempool_parser.set_defaults(handler=handle_blockchain_mempool) - - messaging_parser = subparsers.add_parser("messaging", help="Messaging system and forum") - messaging_parser.set_defaults(handler=lambda parsed, parser=messaging_parser: parser.print_help()) - messaging_subparsers = messaging_parser.add_subparsers(dest="messaging_action") - - messaging_deploy_parser = messaging_subparsers.add_parser("deploy", help="Deploy messaging contract") - messaging_deploy_parser.add_argument("--chain-id", help="Chain ID") - messaging_deploy_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_deploy_parser.set_defaults(handler=handle_messaging_deploy) - - messaging_state_parser = messaging_subparsers.add_parser("state", help="Get contract state") - messaging_state_parser.add_argument("--chain-id", help="Chain ID") - messaging_state_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_state_parser.set_defaults(handler=handle_messaging_state) - - messaging_topics_parser = messaging_subparsers.add_parser("topics", help="List forum topics") - messaging_topics_parser.add_argument("--chain-id", help="Chain ID") - messaging_topics_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_topics_parser.set_defaults(handler=handle_messaging_topics) - - messaging_create_topic_parser = messaging_subparsers.add_parser("create-topic", help="Create forum topic") - messaging_create_topic_parser.add_argument("--title", required=True, help="Topic title") - messaging_create_topic_parser.add_argument("--content", required=True, help="Topic content") - messaging_create_topic_parser.add_argument("--wallet", help="Wallet address for authentication") - messaging_create_topic_parser.add_argument("--password") - messaging_create_topic_parser.add_argument("--password-file") - messaging_create_topic_parser.add_argument("--chain-id", help="Chain ID") - messaging_create_topic_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_create_topic_parser.set_defaults(handler=handle_messaging_create_topic) - - messaging_messages_parser = messaging_subparsers.add_parser("messages", help="Get topic messages") - messaging_messages_parser.add_argument("--topic-id", required=True, help="Topic ID") - messaging_messages_parser.add_argument("--chain-id", help="Chain ID") - messaging_messages_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_messages_parser.set_defaults(handler=handle_messaging_messages) - - messaging_post_parser = messaging_subparsers.add_parser("post", help="Post message") - messaging_post_parser.add_argument("--topic-id", required=True, help="Topic ID") - messaging_post_parser.add_argument("--content", required=True, help="Message content") - messaging_post_parser.add_argument("--wallet", help="Wallet address for authentication") - messaging_post_parser.add_argument("--password") - messaging_post_parser.add_argument("--password-file") - messaging_post_parser.add_argument("--chain-id", help="Chain ID") - messaging_post_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_post_parser.set_defaults(handler=handle_messaging_post) - - messaging_vote_parser = messaging_subparsers.add_parser("vote", help="Vote on message") - messaging_vote_parser.add_argument("--message-id", required=True, help="Message ID") - messaging_vote_parser.add_argument("--vote", required=True, help="Vote (up/down)") - messaging_vote_parser.add_argument("--wallet", help="Wallet address for authentication") - messaging_vote_parser.add_argument("--password") - messaging_vote_parser.add_argument("--password-file") - messaging_vote_parser.add_argument("--chain-id", help="Chain ID") - messaging_vote_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_vote_parser.set_defaults(handler=handle_messaging_vote) - - messaging_search_parser = messaging_subparsers.add_parser("search", help="Search messages") - messaging_search_parser.add_argument("--query", required=True, help="Search query") - messaging_search_parser.add_argument("--chain-id", help="Chain ID") - messaging_search_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_search_parser.set_defaults(handler=handle_messaging_search) - - messaging_reputation_parser = messaging_subparsers.add_parser("reputation", help="Get agent reputation") - messaging_reputation_parser.add_argument("--agent-id", required=True, help="Agent ID") - messaging_reputation_parser.add_argument("--chain-id", help="Chain ID") - messaging_reputation_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_reputation_parser.set_defaults(handler=handle_messaging_reputation) - - messaging_moderate_parser = messaging_subparsers.add_parser("moderate", help="Moderate message") - messaging_moderate_parser.add_argument("--message-id", required=True, help="Message ID") - messaging_moderate_parser.add_argument("--action", required=True, help="Action (approve/reject)") - messaging_moderate_parser.add_argument("--wallet", help="Wallet address for authentication") - messaging_moderate_parser.add_argument("--password") - messaging_moderate_parser.add_argument("--password-file") - messaging_moderate_parser.add_argument("--chain-id", help="Chain ID") - messaging_moderate_parser.add_argument("--rpc-url", default=default_rpc_url) - messaging_moderate_parser.set_defaults(handler=handle_messaging_moderate) - - network_parser = subparsers.add_parser("network", help="Peer connectivity and sync") - network_parser.set_defaults(handler=handle_network_status) - network_subparsers = network_parser.add_subparsers(dest="network_action") - - network_status_parser = network_subparsers.add_parser("status", help="Show network status") - network_status_parser.add_argument("--rpc-url", default=default_rpc_url) - network_status_parser.set_defaults(handler=handle_network_status) - - network_peers_parser = network_subparsers.add_parser("peers", help="List peers") - network_peers_parser.add_argument("--rpc-url", default=default_rpc_url) - network_peers_parser.set_defaults(handler=handle_network_peers) - - network_sync_parser = network_subparsers.add_parser("sync", help="Show sync status") - network_sync_parser.add_argument("--rpc-url", default=default_rpc_url) - network_sync_parser.set_defaults(handler=handle_network_sync) - - network_ping_parser = network_subparsers.add_parser("ping", help="Ping a node") - network_ping_parser.add_argument("node", nargs="?") - network_ping_parser.add_argument("--node", dest="node_opt", help=argparse.SUPPRESS) - network_ping_parser.add_argument("--rpc-url", default=default_rpc_url) - network_ping_parser.set_defaults(handler=handle_network_ping) - - network_propagate_parser = network_subparsers.add_parser("propagate", help="Propagate test data") - network_propagate_parser.add_argument("data", nargs="?") - network_propagate_parser.add_argument("--data", dest="data_opt", help=argparse.SUPPRESS) - network_propagate_parser.add_argument("--rpc-url", default=default_rpc_url) - network_propagate_parser.set_defaults(handler=handle_network_propagate) - - network_force_sync_parser = network_subparsers.add_parser("force-sync", help="Force reorg to specified peer") - network_force_sync_parser.add_argument("--peer", required=True, help="Peer to sync from") - network_force_sync_parser.add_argument("--chain-id", help="Chain ID") - network_force_sync_parser.add_argument("--rpc-url", default=default_rpc_url) - network_force_sync_parser.set_defaults(handler=handle_network_force_sync) - - market_parser = subparsers.add_parser("market", help="Marketplace listings and offers") - market_parser.set_defaults(handler=lambda parsed, parser=market_parser: parser.print_help()) - market_subparsers = market_parser.add_subparsers(dest="market_action") - - # GPU marketplace subcommands - market_gpu_parser = market_subparsers.add_parser("gpu", help="GPU marketplace operations") - market_gpu_parser.set_defaults(handler=lambda parsed, parser=market_gpu_parser: parser.print_help()) - market_gpu_subparsers = market_gpu_parser.add_subparsers(dest="gpu_action") - - market_gpu_register_parser = market_gpu_subparsers.add_parser("register", help="Register GPU on marketplace") - market_gpu_register_parser.add_argument("--name", help="GPU name/model") - market_gpu_register_parser.add_argument("--memory", type=int, help="GPU memory in GB") - market_gpu_register_parser.add_argument("--cuda-cores", type=int, help="Number of CUDA cores") - market_gpu_register_parser.add_argument("--compute-capability", help="Compute capability (e.g., 8.9)") - market_gpu_register_parser.add_argument("--price-per-hour", type=float, required=True, help="Price per hour in AIT") - market_gpu_register_parser.add_argument("--description", help="GPU description") - market_gpu_register_parser.add_argument("--miner-id", help="Miner ID") - market_gpu_register_parser.add_argument("--force", action="store_true", help="Force registration without hardware validation") - market_gpu_register_parser.add_argument("--coordinator-url", default=default_coordinator_url) - market_gpu_register_parser.set_defaults(handler=handle_market_gpu_register) - - market_gpu_list_parser = market_gpu_subparsers.add_parser("list", help="List available GPUs") - market_gpu_list_parser.add_argument("--available", action="store_true", help="Show only available GPUs") - market_gpu_list_parser.add_argument("--price-max", type=float, help="Maximum price per hour") - market_gpu_list_parser.add_argument("--region", help="Filter by region") - market_gpu_list_parser.add_argument("--model", help="Filter by GPU model") - market_gpu_list_parser.add_argument("--limit", type=int, default=100, help="Maximum number of results") - market_gpu_list_parser.add_argument("--coordinator-url", default=default_coordinator_url) - market_gpu_list_parser.set_defaults(handler=handle_market_gpu_list) - - market_list_parser = market_subparsers.add_parser("list", help="List marketplace items") - market_list_parser.add_argument("--chain-id", help="Chain ID") - market_list_parser.add_argument("--coordinator-url", default=default_coordinator_url) - market_list_parser.set_defaults(handler=handle_market_listings) - - market_create_parser = market_subparsers.add_parser("create", help="Create a marketplace listing") - market_create_parser.add_argument("--wallet", required=True) - market_create_parser.add_argument("--type", dest="item_type", required=True) - market_create_parser.add_argument("--price", type=float, required=True) - market_create_parser.add_argument("--description") - market_create_parser.add_argument("--password") - market_create_parser.add_argument("--password-file") - market_create_parser.add_argument("--chain-id", help="Chain ID") - market_create_parser.add_argument("--coordinator-url", default=default_coordinator_url) - market_create_parser.set_defaults(handler=handle_market_create) - - market_search_parser = market_subparsers.add_parser("search", help="Search marketplace items") - market_search_parser.add_argument("--rpc-url", default=default_rpc_url) - market_search_parser.set_defaults(handler=handle_market_listings) # Reuse listings for now - - market_mine_parser = market_subparsers.add_parser("my-listings", help="Show your marketplace listings") - market_mine_parser.add_argument("--wallet") - market_mine_parser.add_argument("--rpc-url", default=default_rpc_url) - market_mine_parser.set_defaults(handler=handle_market_listings) # Reuse listings for now - - market_get_parser = market_subparsers.add_parser("get", help="Get listing by ID") - market_get_parser.add_argument("--listing-id", required=True) - market_get_parser.add_argument("--chain-id", help="Chain ID") - market_get_parser.add_argument("--rpc-url", default=default_rpc_url) - market_get_parser.set_defaults(handler=handle_market_get) - - market_delete_parser = market_subparsers.add_parser("delete", help="Delete listing") - market_delete_parser.add_argument("--listing-id", required=True) - market_delete_parser.add_argument("--wallet", required=True) - market_delete_parser.add_argument("--password") - market_delete_parser.add_argument("--password-file") - market_delete_parser.add_argument("--chain-id", help="Chain ID") - market_delete_parser.add_argument("--coordinator-url", default=default_coordinator_url) - market_delete_parser.set_defaults(handler=handle_market_delete) - - market_buy_parser = market_subparsers.add_parser("buy", help="Buy from marketplace") - market_buy_parser.add_argument("--item", required=True) - market_buy_parser.add_argument("--wallet", required=True) - market_buy_parser.add_argument("--password") - market_buy_parser.add_argument("--rpc-url", default=default_rpc_url) - market_buy_parser.set_defaults(handler=handle_market_listings) # Placeholder - - market_sell_parser = market_subparsers.add_parser("sell", help="Sell on marketplace") - market_sell_parser.add_argument("--item", required=True) - market_sell_parser.add_argument("--price", type=float, required=True) - market_sell_parser.add_argument("--wallet", required=True) - market_sell_parser.add_argument("--password") - market_sell_parser.add_argument("--rpc-url", default=default_rpc_url) - market_sell_parser.set_defaults(handler=handle_market_create) # Reuse create - - market_orders_parser = market_subparsers.add_parser("orders", help="Show marketplace orders") - market_orders_parser.add_argument("--wallet") - market_orders_parser.add_argument("--rpc-url", default=default_rpc_url) - market_orders_parser.set_defaults(handler=handle_market_listings) # Reuse listings for now - - ai_parser = subparsers.add_parser("ai", help="AI job submission and inspection") - ai_parser.set_defaults(handler=lambda parsed, parser=ai_parser: parser.print_help()) - ai_subparsers = ai_parser.add_subparsers(dest="ai_action") - - ai_submit_parser = ai_subparsers.add_parser("submit", help="Submit an AI job") - ai_submit_parser.add_argument("wallet_name", nargs="?") - ai_submit_parser.add_argument("job_type_arg", nargs="?") - ai_submit_parser.add_argument("prompt_arg", nargs="?") - ai_submit_parser.add_argument("payment_arg", nargs="?") - ai_submit_parser.add_argument("--wallet") - ai_submit_parser.add_argument("--type", dest="job_type") - ai_submit_parser.add_argument("--prompt") - ai_submit_parser.add_argument("--payment", type=float) - ai_submit_parser.add_argument("--password") - ai_submit_parser.add_argument("--password-file") - ai_submit_parser.add_argument("--chain-id", help="Chain ID") - ai_submit_parser.add_argument("--rpc-url", default=default_rpc_url) - ai_submit_parser.set_defaults(handler=handle_ai_submit) - - ai_jobs_parser = ai_subparsers.add_parser("jobs", help="List AI jobs") - ai_jobs_parser.add_argument("--limit", type=int, default=10) - ai_jobs_parser.add_argument("--chain-id", help="Chain ID") - ai_jobs_parser.add_argument("--rpc-url", default=default_rpc_url) - ai_jobs_parser.set_defaults(handler=handle_ai_jobs) - - ai_status_parser = ai_subparsers.add_parser("status", help="Show AI job status") - ai_status_parser.add_argument("job_id_arg", nargs="?") - ai_status_parser.add_argument("--job-id", dest="job_id") - ai_status_parser.add_argument("--wallet") - ai_status_parser.add_argument("--chain-id", help="Chain ID") - ai_status_parser.add_argument("--rpc-url", default=default_rpc_url) - ai_status_parser.set_defaults(handler=handle_ai_job) - - ai_service_parser = ai_subparsers.add_parser("service", help="AI service management") - ai_service_subparsers = ai_service_parser.add_subparsers(dest="ai_service_action") - - ai_service_list_parser = ai_service_subparsers.add_parser("list", help="List available AI services") - ai_service_list_parser.set_defaults(handler=handle_ai_service_list) - - ai_service_status_parser = ai_service_subparsers.add_parser("status", help="Check AI service status") - ai_service_status_parser.add_argument("--name", help="Service name to check") - ai_service_status_parser.set_defaults(handler=handle_ai_service_status) - - ai_service_test_parser = ai_service_subparsers.add_parser("test", help="Test AI service endpoint") - ai_service_test_parser.add_argument("--name", help="Service name to test") - ai_service_test_parser.set_defaults(handler=handle_ai_service_test) - - ai_results_parser = ai_subparsers.add_parser("results", help="Show AI job results") - ai_results_parser.add_argument("job_id_arg", nargs="?") - ai_results_parser.add_argument("--job-id", dest="job_id") - ai_results_parser.add_argument("--wallet") - ai_results_parser.add_argument("--chain-id", help="Chain ID") - ai_results_parser.add_argument("--rpc-url", default=default_rpc_url) - ai_results_parser.set_defaults(handler=handle_ai_job) # Reuse job handler - - ai_cancel_parser = ai_subparsers.add_parser("cancel", help="Cancel AI job") - ai_cancel_parser.add_argument("job_id_arg", nargs="?") - ai_cancel_parser.add_argument("--job-id", dest="job_id") - ai_cancel_parser.add_argument("--wallet", required=True) - ai_cancel_parser.add_argument("--password") - ai_cancel_parser.add_argument("--password-file") - ai_cancel_parser.add_argument("--chain-id", help="Chain ID") - ai_cancel_parser.add_argument("--rpc-url", default=default_rpc_url) - ai_cancel_parser.set_defaults(handler=handle_ai_cancel) - - ai_stats_parser = ai_subparsers.add_parser("stats", help="AI service statistics") - ai_stats_parser.add_argument("--chain-id", help="Chain ID") - ai_stats_parser.add_argument("--rpc-url", default=default_rpc_url) - ai_stats_parser.set_defaults(handler=handle_ai_stats) - - mining_parser = subparsers.add_parser("mining", help="Mining lifecycle and rewards") - mining_parser.set_defaults(handler=handle_mining_action, mining_action="status") - mining_subparsers = mining_parser.add_subparsers(dest="mining_action") - - mining_status_parser = mining_subparsers.add_parser("status", help="Show mining status") - mining_status_parser.add_argument("--wallet") - mining_status_parser.add_argument("--rpc-url", default=default_rpc_url) - mining_status_parser.set_defaults(handler=handle_mining_action, mining_action="status") - - mining_start_parser = mining_subparsers.add_parser("start", help="Start mining") - mining_start_parser.add_argument("--wallet") - mining_start_parser.add_argument("--rpc-url", default=default_rpc_url) - mining_start_parser.set_defaults(handler=handle_mining_action, mining_action="start") - - mining_stop_parser = mining_subparsers.add_parser("stop", help="Stop mining") - mining_stop_parser.add_argument("--rpc-url", default=default_rpc_url) - mining_stop_parser.set_defaults(handler=handle_mining_action, mining_action="stop") - - mining_rewards_parser = mining_subparsers.add_parser("rewards", help="Show mining rewards") - mining_rewards_parser.add_argument("--wallet") - mining_rewards_parser.add_argument("--rpc-url", default=default_rpc_url) - mining_rewards_parser.set_defaults(handler=handle_mining_action, mining_action="rewards") - - analytics_parser = subparsers.add_parser("analytics", help="Blockchain analytics and statistics") - analytics_parser.set_defaults(handler=lambda parsed, parser=analytics_parser: parser.print_help()) - analytics_subparsers = analytics_parser.add_subparsers(dest="analytics_action") - - analytics_blocks_parser = analytics_subparsers.add_parser("blocks", help="Block analytics") - analytics_blocks_parser.add_argument("--limit", type=int, default=10) - analytics_blocks_parser.add_argument("--rpc-url", default=default_rpc_url) - analytics_blocks_parser.set_defaults(handler=handle_analytics, type="blocks") - - analytics_report_parser = analytics_subparsers.add_parser("report", help="Generate analytics report") - analytics_report_parser.add_argument("--type", choices=["performance", "transactions", "all"], default="all") - analytics_report_parser.add_argument("--rpc-url", default=default_rpc_url) - analytics_report_parser.set_defaults(handler=handle_analytics, type="report") - - analytics_metrics_parser = analytics_subparsers.add_parser("metrics", help="Show performance metrics") - analytics_metrics_parser.add_argument("--limit", type=int, default=10) - analytics_metrics_parser.add_argument("--rpc-url", default=default_rpc_url) - analytics_metrics_parser.set_defaults(handler=handle_analytics, type="metrics") - - analytics_export_parser = analytics_subparsers.add_parser("export", help="Export analytics data") - analytics_export_parser.add_argument("--format", choices=["json", "csv"], default="json") - analytics_export_parser.add_argument("--output") - analytics_export_parser.add_argument("--rpc-url", default=default_rpc_url) - analytics_export_parser.set_defaults(handler=handle_analytics, type="export") - - system_parser = subparsers.add_parser("system", help="System health and overview") - system_parser.set_defaults(handler=handle_system_status) - system_subparsers = system_parser.add_subparsers(dest="system_action") - - system_status_parser = system_subparsers.add_parser("status", help="Show system status") - system_status_parser.set_defaults(handler=handle_system_status) - - agent_parser = subparsers.add_parser("agent", help="AI agent workflow orchestration") - agent_parser.set_defaults(handler=lambda parsed, parser=agent_parser: parser.print_help()) - agent_subparsers = agent_parser.add_subparsers(dest="agent_action") - - agent_create_parser = agent_subparsers.add_parser("create", help="Create an agent workflow") - agent_create_parser.add_argument("--name", required=True) - agent_create_parser.add_argument("--description") - agent_create_parser.add_argument("--workflow-file") - agent_create_parser.add_argument("--verification", choices=["basic", "full", "zero-knowledge"], default="basic") - agent_create_parser.add_argument("--max-execution-time", type=int, default=3600) - agent_create_parser.add_argument("--max-cost-budget", type=float, default=0.0) - agent_create_parser.set_defaults(handler=handle_agent_action) - - agent_execute_parser = agent_subparsers.add_parser("execute", help="Execute an agent workflow") - agent_execute_parser.add_argument("--name", required=True) - agent_execute_parser.add_argument("--input-data") - agent_execute_parser.add_argument("--wallet") - agent_execute_parser.add_argument("--priority", choices=["low", "medium", "high"], default="medium") - agent_execute_parser.set_defaults(handler=handle_agent_action) - - agent_status_parser = agent_subparsers.add_parser("status", help="Show agent status") - agent_status_parser.add_argument("--name") - agent_status_parser.add_argument("--execution-id") - agent_status_parser.set_defaults(handler=handle_agent_action) - - agent_list_parser = agent_subparsers.add_parser("list", help="List agents") - agent_list_parser.add_argument("--status", choices=["active", "completed", "failed"]) - agent_list_parser.set_defaults(handler=handle_agent_action) - - agent_message_parser = agent_subparsers.add_parser("message", help="Send message to agent") - agent_message_parser.add_argument("--agent", required=True) - agent_message_parser.add_argument("--message", required=True) - agent_message_parser.add_argument("--wallet", required=True) - agent_message_parser.add_argument("--password") - agent_message_parser.add_argument("--password-file") - agent_message_parser.add_argument("--rpc-url", default=default_rpc_url) - agent_message_parser.set_defaults(handler=handle_agent_action, agent_action="message") - - agent_messages_parser = agent_subparsers.add_parser("messages", help="List agent messages") - agent_messages_parser.add_argument("--agent", required=True) - agent_messages_parser.add_argument("--wallet") - agent_messages_parser.add_argument("--rpc-url", default=default_rpc_url) - agent_messages_parser.set_defaults(handler=handle_agent_action, agent_action="messages") - - openclaw_parser = subparsers.add_parser("openclaw", help="OpenClaw ecosystem operations") - openclaw_parser.set_defaults(handler=lambda parsed, parser=openclaw_parser: parser.print_help()) - openclaw_subparsers = openclaw_parser.add_subparsers(dest="openclaw_action") - - openclaw_deploy_parser = openclaw_subparsers.add_parser("deploy", help="Deploy an OpenClaw agent") - openclaw_deploy_parser.add_argument("--agent-file", required=True) - openclaw_deploy_parser.add_argument("--wallet", required=True) - openclaw_deploy_parser.add_argument("--environment", choices=["dev", "staging", "prod"], default="dev") - openclaw_deploy_parser.set_defaults(handler=handle_openclaw_action) - - openclaw_monitor_parser = openclaw_subparsers.add_parser("monitor", help="Monitor OpenClaw performance") - openclaw_monitor_parser.add_argument("--agent-id") - openclaw_monitor_parser.add_argument("--metrics", choices=["performance", "cost", "errors", "all"], default="all") - openclaw_monitor_parser.set_defaults(handler=handle_openclaw_action) - - openclaw_market_parser = openclaw_subparsers.add_parser("market", help="Manage OpenClaw marketplace activity") - openclaw_market_parser.add_argument("market_action", nargs="?", choices=["list", "publish", "purchase", "evaluate"]) - openclaw_market_parser.add_argument("--action", dest="market_action_opt", choices=["list", "publish", "purchase", "evaluate"], help=argparse.SUPPRESS) - openclaw_market_parser.add_argument("--agent-id") - openclaw_market_parser.add_argument("--price", type=float) - openclaw_market_parser.set_defaults(handler=handle_openclaw_action, openclaw_action="market") - - workflow_parser = subparsers.add_parser("workflow", help="Workflow templates and execution") - workflow_parser.set_defaults(handler=lambda parsed, parser=workflow_parser: parser.print_help()) - workflow_subparsers = workflow_parser.add_subparsers(dest="workflow_action") - - workflow_create_parser = workflow_subparsers.add_parser("create", help="Create a workflow") - workflow_create_parser.add_argument("--name", required=True) - workflow_create_parser.add_argument("--template") - workflow_create_parser.add_argument("--config-file") - workflow_create_parser.set_defaults(handler=handle_workflow_action) - - workflow_run_parser = workflow_subparsers.add_parser("run", help="Run a workflow") - workflow_run_parser.add_argument("--name", required=True) - workflow_run_parser.add_argument("--params") - workflow_run_parser.add_argument("--async-exec", action="store_true") - workflow_run_parser.set_defaults(handler=handle_workflow_action) - - workflow_schedule_parser = workflow_subparsers.add_parser("schedule", help="Schedule a workflow") - workflow_schedule_parser.add_argument("--name", required=True) - workflow_schedule_parser.add_argument("--cron", required=True) - workflow_schedule_parser.add_argument("--params") - workflow_schedule_parser.set_defaults(handler=handle_workflow_action, workflow_action="schedule") - - workflow_monitor_parser = workflow_subparsers.add_parser("monitor", help="Monitor workflow execution") - workflow_monitor_parser.add_argument("--name") - workflow_monitor_parser.add_argument("--execution-id") - workflow_monitor_parser.set_defaults(handler=handle_workflow_action, workflow_action="monitor") - - resource_parser = subparsers.add_parser("resource", help="Resource utilization and allocation") - resource_parser.set_defaults(handler=lambda parsed, parser=resource_parser: parser.print_help()) - resource_subparsers = resource_parser.add_subparsers(dest="resource_action") - - resource_status_parser = resource_subparsers.add_parser("status", help="Show resource status") - resource_status_parser.add_argument("--type", choices=["cpu", "memory", "storage", "network", "all"], default="all") - resource_status_parser.set_defaults(handler=handle_resource_action) - - resource_allocate_parser = resource_subparsers.add_parser("allocate", help="Allocate resources") - resource_allocate_parser.add_argument("--agent-id", required=True) - resource_allocate_parser.add_argument("--cpu", type=float) - resource_allocate_parser.add_argument("--memory", type=int) - resource_allocate_parser.add_argument("--duration", type=int) - resource_allocate_parser.set_defaults(handler=handle_resource_action) - - resource_optimize_parser = resource_subparsers.add_parser("optimize", help="Optimize resource usage") - resource_optimize_parser.add_argument("--agent-id") - resource_optimize_parser.add_argument("--target", choices=["cpu", "memory", "all"], default="all") - resource_optimize_parser.set_defaults(handler=handle_resource_action, resource_action="optimize") - - resource_benchmark_parser = resource_subparsers.add_parser("benchmark", help="Run resource benchmark") - resource_benchmark_parser.add_argument("--type", choices=["cpu", "memory", "io", "all"], default="all") - resource_benchmark_parser.set_defaults(handler=handle_resource_action, resource_action="benchmark") - - resource_monitor_parser = resource_subparsers.add_parser("monitor", help="Monitor resource utilization") - resource_monitor_parser.add_argument("--interval", type=int, default=5, help="Monitoring interval in seconds") - resource_monitor_parser.add_argument("--duration", type=int, default=60, help="Monitoring duration in seconds") - resource_monitor_parser.set_defaults(handler=handle_resource_action, resource_action="monitor") - - economics_parser = subparsers.add_parser("economics", help="Economic intelligence and modeling") - economics_parser.set_defaults(handler=lambda parsed, parser=economics_parser: parser.print_help()) - economics_subparsers = economics_parser.add_subparsers(dest="economics_action") - - economics_distributed_parser = economics_subparsers.add_parser("distributed", help="Distributed cost optimization") - economics_distributed_parser.add_argument("--cost-optimize", action="store_true") - economics_distributed_parser.set_defaults(handler=handle_economics_action) - - economics_market_parser = economics_subparsers.add_parser("market", help="Market analysis") - economics_market_parser.add_argument("--analyze", action="store_true") - economics_market_parser.set_defaults(handler=handle_economics_action) - - economics_trends_parser = economics_subparsers.add_parser("trends", help="Economic trends analysis") - economics_trends_parser.add_argument("--period") - economics_trends_parser.set_defaults(handler=handle_economics_action) - - economics_optimize_parser = economics_subparsers.add_parser("optimize", help="Optimize economic strategy") - economics_optimize_parser.add_argument("--target", choices=["revenue", "cost", "all"], default="all") - economics_optimize_parser.set_defaults(handler=handle_economics_action) - - genesis_parser = subparsers.add_parser("genesis", help="Genesis block and wallet generation") - genesis_parser.set_defaults(handler=lambda parsed, parser=genesis_parser: parser.print_help()) - genesis_subparsers = genesis_parser.add_subparsers(dest="genesis_action") - - genesis_init_parser = genesis_subparsers.add_parser("init", help="Initialize genesis block and wallet") - genesis_init_parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID for genesis") - genesis_init_parser.add_argument("--create-wallet", action="store_true", help="Create genesis wallet with secure random key") - genesis_init_parser.add_argument("--password", help="Wallet password (auto-generated if not provided)") - genesis_init_parser.add_argument("--proposer", help="Proposer address (defaults to genesis wallet)") - genesis_init_parser.add_argument("--force", action="store_true", help="Force overwrite existing genesis") - genesis_init_parser.add_argument("--register-service", action="store_true", help="Register genesis wallet with wallet service") - genesis_init_parser.add_argument("--service-url", default="http://localhost:8003", help="Wallet service URL") - genesis_init_parser.set_defaults(handler=handle_genesis_init) - - genesis_verify_parser = genesis_subparsers.add_parser("verify", help="Verify genesis block and wallet configuration") - genesis_verify_parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID to verify") - genesis_verify_parser.set_defaults(handler=handle_genesis_verify) - - genesis_info_parser = genesis_subparsers.add_parser("info", help="Show genesis block information") - genesis_info_parser.add_argument("--chain-id", default="ait-mainnet", help="Chain ID to show info for") - genesis_info_parser.set_defaults(handler=handle_genesis_info) - - cluster_parser = subparsers.add_parser("cluster", help="Cluster management") - cluster_parser.set_defaults(handler=lambda parsed, parser=cluster_parser: parser.print_help()) - cluster_subparsers = cluster_parser.add_subparsers(dest="cluster_action") - - cluster_status_parser = cluster_subparsers.add_parser("status", help="Show cluster status") - cluster_status_parser.add_argument("--nodes", nargs="*", default=["aitbc", "aitbc1"]) - cluster_status_parser.set_defaults(handler=handle_network_status) - - cluster_sync_parser = cluster_subparsers.add_parser("sync", help="Sync cluster nodes") - cluster_sync_parser.add_argument("--all", action="store_true") - cluster_sync_parser.set_defaults(handler=handle_cluster_action) - - cluster_balance_parser = cluster_subparsers.add_parser("balance", help="Balance workload across nodes") - cluster_balance_parser.add_argument("--workload", action="store_true") - cluster_balance_parser.set_defaults(handler=handle_cluster_action) - - performance_parser = subparsers.add_parser("performance", help="Performance optimization") - performance_parser.set_defaults(handler=lambda parsed, parser=performance_parser: parser.print_help()) - performance_subparsers = performance_parser.add_subparsers(dest="performance_action") - - performance_benchmark_parser = performance_subparsers.add_parser("benchmark", help="Run performance benchmark") - performance_benchmark_parser.add_argument("--suite", choices=["comprehensive", "quick", "custom"], default="comprehensive") - performance_benchmark_parser.set_defaults(handler=handle_performance_action) - - performance_optimize_parser = performance_subparsers.add_parser("optimize", help="Optimize performance") - performance_optimize_parser.add_argument("--target", choices=["latency", "throughput", "all"], default="all") - performance_optimize_parser.set_defaults(handler=handle_performance_action) - - performance_tune_parser = performance_subparsers.add_parser("tune", help="Tune system parameters") - performance_tune_parser.add_argument("--parameters", action="store_true") - performance_tune_parser.add_argument("--aggressive", action="store_true") - performance_tune_parser.set_defaults(handler=handle_performance_action) - - security_parser = subparsers.add_parser("security", help="Security audit and scanning") - security_parser.set_defaults(handler=lambda parsed, parser=security_parser: parser.print_help()) - security_subparsers = security_parser.add_subparsers(dest="security_action") - - security_audit_parser = security_subparsers.add_parser("audit", help="Run security audit") - security_audit_parser.add_argument("--comprehensive", action="store_true") - security_audit_parser.set_defaults(handler=handle_security_action) - - security_scan_parser = security_subparsers.add_parser("scan", help="Scan for vulnerabilities") - security_scan_parser.add_argument("--vulnerabilities", action="store_true") - security_scan_parser.set_defaults(handler=handle_security_action) - - security_patch_parser = security_subparsers.add_parser("patch", help="Check for security patches") - security_patch_parser.add_argument("--critical", action="store_true") - security_patch_parser.set_defaults(handler=handle_security_action) - - compliance_parser = subparsers.add_parser("compliance", help="Compliance checking and reporting") - compliance_parser.set_defaults(handler=lambda parsed, parser=compliance_parser: parser.print_help()) - compliance_subparsers = compliance_parser.add_subparsers(dest="compliance_action") - - compliance_check_parser = compliance_subparsers.add_parser("check", help="Check compliance status") - compliance_check_parser.add_argument("--standard", choices=["gdpr", "hipaa", "soc2", "all"], default="gdpr") - compliance_check_parser.set_defaults(handler=handle_system_status) - - compliance_report_parser = compliance_subparsers.add_parser("report", help="Generate compliance report") - compliance_report_parser.add_argument("--format", choices=["detailed", "summary", "json"], default="detailed") - compliance_report_parser.set_defaults(handler=handle_system_status) - - simulate_parser = subparsers.add_parser("simulate", help="Simulation utilities") - simulate_parser.set_defaults(handler=lambda parsed, parser=simulate_parser: parser.print_help()) - simulate_subparsers = simulate_parser.add_subparsers(dest="simulate_command") - - simulate_blockchain_parser = simulate_subparsers.add_parser("blockchain", help="Simulate blockchain activity") - simulate_blockchain_parser.add_argument("--blocks", type=int, default=10) - simulate_blockchain_parser.add_argument("--transactions", type=int, default=50) - simulate_blockchain_parser.add_argument("--delay", type=float, default=1.0) - simulate_blockchain_parser.set_defaults(handler=handle_simulate_action) - - simulate_wallets_parser = simulate_subparsers.add_parser("wallets", help="Simulate wallet activity") - simulate_wallets_parser.add_argument("--wallets", type=int, default=5) - simulate_wallets_parser.add_argument("--balance", type=float, default=1000.0) - simulate_wallets_parser.add_argument("--transactions", type=int, default=20) - simulate_wallets_parser.add_argument("--amount-range", default="1.0-100.0") - simulate_wallets_parser.set_defaults(handler=handle_simulate_action) - - simulate_price_parser = simulate_subparsers.add_parser("price", help="Simulate price movement") - simulate_price_parser.add_argument("--price", type=float, default=100.0) - simulate_price_parser.add_argument("--volatility", type=float, default=0.05) - simulate_price_parser.add_argument("--timesteps", type=int, default=100) - simulate_price_parser.add_argument("--delay", type=float, default=0.1) - simulate_price_parser.set_defaults(handler=handle_simulate_action) - - simulate_network_parser = simulate_subparsers.add_parser("network", help="Simulate network topology") - simulate_network_parser.add_argument("--nodes", type=int, default=3) - simulate_network_parser.add_argument("--network-delay", type=float, default=0.1) - simulate_network_parser.add_argument("--failure-rate", type=float, default=0.05) - simulate_network_parser.set_defaults(handler=handle_simulate_action) - - simulate_ai_jobs_parser = simulate_subparsers.add_parser("ai-jobs", help="Simulate AI job traffic") - simulate_ai_jobs_parser.add_argument("--jobs", type=int, default=10) - simulate_ai_jobs_parser.add_argument("--models", default="text-generation") - simulate_ai_jobs_parser.add_argument("--duration-range", default="30-300") - simulate_ai_jobs_parser.set_defaults(handler=handle_simulate_action) - - pool_hub_parser = subparsers.add_parser("pool-hub", help="Pool hub management for SLA monitoring and billing") - pool_hub_parser.set_defaults(handler=lambda parsed, parser=pool_hub_parser: parser.print_help()) - pool_hub_subparsers = pool_hub_parser.add_subparsers(dest="pool_hub_action") - - pool_hub_sla_metrics_parser = pool_hub_subparsers.add_parser("sla-metrics", help="Get SLA metrics for miner or all miners") - pool_hub_sla_metrics_parser.add_argument("miner_id", nargs="?") - pool_hub_sla_metrics_parser.add_argument("--test-mode", action="store_true") - pool_hub_sla_metrics_parser.set_defaults(handler=handle_pool_hub_sla_metrics) - - pool_hub_sla_violations_parser = pool_hub_subparsers.add_parser("sla-violations", help="Get SLA violations") - pool_hub_sla_violations_parser.add_argument("--test-mode", action="store_true") - pool_hub_sla_violations_parser.set_defaults(handler=handle_pool_hub_sla_violations) - - pool_hub_capacity_snapshots_parser = pool_hub_subparsers.add_parser("capacity-snapshots", help="Get capacity planning snapshots") - pool_hub_capacity_snapshots_parser.add_argument("--test-mode", action="store_true") - pool_hub_capacity_snapshots_parser.set_defaults(handler=handle_pool_hub_capacity_snapshots) - - pool_hub_capacity_forecast_parser = pool_hub_subparsers.add_parser("capacity-forecast", help="Get capacity forecast") - pool_hub_capacity_forecast_parser.add_argument("--test-mode", action="store_true") - pool_hub_capacity_forecast_parser.set_defaults(handler=handle_pool_hub_capacity_forecast) - - pool_hub_capacity_recommendations_parser = pool_hub_subparsers.add_parser("capacity-recommendations", help="Get scaling recommendations") - pool_hub_capacity_recommendations_parser.add_argument("--test-mode", action="store_true") - pool_hub_capacity_recommendations_parser.set_defaults(handler=handle_pool_hub_capacity_recommendations) - - pool_hub_billing_usage_parser = pool_hub_subparsers.add_parser("billing-usage", help="Get billing usage data") - pool_hub_billing_usage_parser.add_argument("--test-mode", action="store_true") - pool_hub_billing_usage_parser.set_defaults(handler=handle_pool_hub_billing_usage) - - pool_hub_billing_sync_parser = pool_hub_subparsers.add_parser("billing-sync", help="Trigger billing sync with coordinator-api") - pool_hub_billing_sync_parser.add_argument("--test-mode", action="store_true") - pool_hub_billing_sync_parser.set_defaults(handler=handle_pool_hub_billing_sync) - - pool_hub_collect_metrics_parser = pool_hub_subparsers.add_parser("collect-metrics", help="Trigger SLA metrics collection") - pool_hub_collect_metrics_parser.add_argument("--test-mode", action="store_true") - pool_hub_collect_metrics_parser.set_defaults(handler=handle_pool_hub_collect_metrics) - - bridge_parser = subparsers.add_parser("bridge", help="Blockchain event bridge management") - bridge_parser.set_defaults(handler=lambda parsed, parser=bridge_parser: parser.print_help()) - bridge_subparsers = bridge_parser.add_subparsers(dest="bridge_action") - - bridge_health_parser = bridge_subparsers.add_parser("health", help="Health check for blockchain event bridge service") - bridge_health_parser.add_argument("--test-mode", action="store_true") - bridge_health_parser.set_defaults(handler=handle_bridge_health) - - bridge_metrics_parser = bridge_subparsers.add_parser("metrics", help="Get Prometheus metrics from blockchain event bridge service") - bridge_metrics_parser.add_argument("--test-mode", action="store_true") - bridge_metrics_parser.set_defaults(handler=handle_bridge_metrics) - - bridge_status_parser = bridge_subparsers.add_parser("status", help="Get detailed status of blockchain event bridge service") - bridge_status_parser.add_argument("--test-mode", action="store_true") - bridge_status_parser.set_defaults(handler=handle_bridge_status) - - bridge_config_parser = bridge_subparsers.add_parser("config", help="Show current configuration of blockchain event bridge service") - bridge_config_parser.add_argument("--test-mode", action="store_true") - bridge_config_parser.set_defaults(handler=handle_bridge_config) - - bridge_restart_parser = bridge_subparsers.add_parser("restart", help="Restart blockchain event bridge service (via systemd)") - bridge_restart_parser.add_argument("--test-mode", action="store_true") - bridge_restart_parser.set_defaults(handler=handle_bridge_restart) - - parsed_args = parser.parse_args(normalize_legacy_args(list(sys.argv[1:] if argv is None else argv))) - if not getattr(parsed_args, "command", None): - parser.print_help() - return - handler = getattr(parsed_args, "handler", None) - if handler is None: - parser.print_help() - return - handler(parsed_args) +if __name__ == "__main__": + raise SystemExit(main())