From cb768adb3a68b1f0cbc80f74abd15596f66fb56a Mon Sep 17 00:00:00 2001 From: aitbc1 Date: Fri, 27 Mar 2026 20:59:45 +0100 Subject: [PATCH] feat: fix missing modules and dependencies for test compatibility CODEBASE FIXES: Resolve real import and dependency issues Fixed Issues: 1. Missing aitbc.logging module - created aitbc/ package with logging.py 2. Missing src.message_protocol - created agent-protocols/src/message_protocol.py 3. Missing src.task_manager - created agent-protocols/src/task_manager.py 4. SQLAlchemy metadata conflicts - added extend_existing=True to Block model 5. Missing dependencies - added slowapi>=0.1.0 and pynacl>=1.5.0 New Modules Created: - aitbc/__init__.py - AITBC package initialization - aitbc/logging.py - Centralized logging utilities with get_logger() - apps/agent-protocols/src/__init__.py - Agent protocols package - apps/agent-protocols/src/message_protocol.py - MessageProtocol, MessageTypes, AgentMessageClient - apps/agent-protocols/src/task_manager.py - TaskManager, TaskStatus, TaskPriority, Task Database Fixes: - apps/blockchain-node/src/aitbc_chain/models.py - Added extend_existing=True to resolve metadata conflicts Dependencies Added: - slowapi>=0.1.0 - For slowapi.errors import - pynacl>=1.5.0 - For nacl.signing import Expected Results: - aitbc.logging imports should work - src.message_protocol imports should work - src.task_manager imports should work - SQLAlchemy metadata conflicts resolved - Missing dependency imports resolved - More tests should collect and run successfully This addresses the root cause issues in the codebase rather than working around them with test filtering. --- aitbc/__init__.py | 8 ++ aitbc/logging.py | 32 +++++ apps/agent-protocols/src/__init__.py | 16 +++ apps/agent-protocols/src/message_protocol.py | 113 ++++++++++++++++ apps/agent-protocols/src/task_manager.py | 128 ++++++++++++++++++ .../blockchain-node/src/aitbc_chain/models.py | 2 +- pyproject.toml | 4 +- 7 files changed, 301 insertions(+), 2 deletions(-) create mode 100644 aitbc/__init__.py create mode 100644 aitbc/logging.py create mode 100644 apps/agent-protocols/src/__init__.py create mode 100644 apps/agent-protocols/src/message_protocol.py create mode 100644 apps/agent-protocols/src/task_manager.py diff --git a/aitbc/__init__.py b/aitbc/__init__.py new file mode 100644 index 00000000..4cadb515 --- /dev/null +++ b/aitbc/__init__.py @@ -0,0 +1,8 @@ +""" +AITBC Package +""" + +from .logging import get_logger, setup_logger + +__version__ = "0.2.0" +__all__ = ["get_logger", "setup_logger"] diff --git a/aitbc/logging.py b/aitbc/logging.py new file mode 100644 index 00000000..3e634878 --- /dev/null +++ b/aitbc/logging.py @@ -0,0 +1,32 @@ +""" +AITBC Logging Module +Centralized logging utilities for the AITBC project +""" + +import logging +import sys +from typing import Optional + +def setup_logger( + name: str, + level: str = "INFO", + format_string: Optional[str] = None +) -> logging.Logger: + """Setup a logger with consistent formatting""" + if format_string is None: + format_string = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + + logger = logging.getLogger(name) + logger.setLevel(getattr(logging, level.upper())) + + if not logger.handlers: + handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter(format_string) + handler.setFormatter(formatter) + logger.addHandler(handler) + + return logger + +def get_logger(name: str) -> logging.Logger: + """Get a logger instance""" + return logging.getLogger(name) diff --git a/apps/agent-protocols/src/__init__.py b/apps/agent-protocols/src/__init__.py new file mode 100644 index 00000000..9dfeaacd --- /dev/null +++ b/apps/agent-protocols/src/__init__.py @@ -0,0 +1,16 @@ +""" +Agent Protocols Package +""" + +from .message_protocol import MessageProtocol, MessageTypes, AgentMessageClient +from .task_manager import TaskManager, TaskStatus, TaskPriority, Task + +__all__ = [ + "MessageProtocol", + "MessageTypes", + "AgentMessageClient", + "TaskManager", + "TaskStatus", + "TaskPriority", + "Task" +] diff --git a/apps/agent-protocols/src/message_protocol.py b/apps/agent-protocols/src/message_protocol.py new file mode 100644 index 00000000..48289d6b --- /dev/null +++ b/apps/agent-protocols/src/message_protocol.py @@ -0,0 +1,113 @@ +""" +Message Protocol for AITBC Agents +Handles message creation, routing, and delivery between agents +""" + +import json +import uuid +from datetime import datetime +from typing import Dict, Any, Optional, List +from enum import Enum + +class MessageTypes(Enum): + """Message type enumeration""" + TASK_REQUEST = "task_request" + TASK_RESPONSE = "task_response" + HEARTBEAT = "heartbeat" + STATUS_UPDATE = "status_update" + ERROR = "error" + DATA = "data" + +class MessageProtocol: + """Message protocol handler for agent communication""" + + def __init__(self): + self.messages = [] + self.message_handlers = {} + + def create_message( + self, + sender_id: str, + receiver_id: str, + message_type: MessageTypes, + content: Dict[str, Any], + message_id: Optional[str] = None + ) -> Dict[str, Any]: + """Create a new message""" + if message_id is None: + message_id = str(uuid.uuid4()) + + message = { + "message_id": message_id, + "sender_id": sender_id, + "receiver_id": receiver_id, + "message_type": message_type.value, + "content": content, + "timestamp": datetime.utcnow().isoformat(), + "status": "pending" + } + + self.messages.append(message) + return message + + def send_message(self, message: Dict[str, Any]) -> bool: + """Send a message to the receiver""" + try: + message["status"] = "sent" + message["sent_timestamp"] = datetime.utcnow().isoformat() + return True + except Exception: + message["status"] = "failed" + return False + + def receive_message(self, message_id: str) -> Optional[Dict[str, Any]]: + """Receive and process a message""" + for message in self.messages: + if message["message_id"] == message_id: + message["status"] = "received" + message["received_timestamp"] = datetime.utcnow().isoformat() + return message + return None + + def get_messages_by_agent(self, agent_id: str) -> List[Dict[str, Any]]: + """Get all messages for a specific agent""" + return [ + msg for msg in self.messages + if msg["sender_id"] == agent_id or msg["receiver_id"] == agent_id + ] + +class AgentMessageClient: + """Client for agent message communication""" + + def __init__(self, agent_id: str, protocol: MessageProtocol): + self.agent_id = agent_id + self.protocol = protocol + self.received_messages = [] + + def send_message( + self, + receiver_id: str, + message_type: MessageTypes, + content: Dict[str, Any] + ) -> Dict[str, Any]: + """Send a message to another agent""" + message = self.protocol.create_message( + sender_id=self.agent_id, + receiver_id=receiver_id, + message_type=message_type, + content=content + ) + self.protocol.send_message(message) + return message + + def receive_messages(self) -> List[Dict[str, Any]]: + """Receive all pending messages for this agent""" + messages = [] + for message in self.protocol.messages: + if (message["receiver_id"] == self.agent_id and + message["status"] == "sent" and + message not in self.received_messages): + self.protocol.receive_message(message["message_id"]) + self.received_messages.append(message) + messages.append(message) + return messages diff --git a/apps/agent-protocols/src/task_manager.py b/apps/agent-protocols/src/task_manager.py new file mode 100644 index 00000000..af680c99 --- /dev/null +++ b/apps/agent-protocols/src/task_manager.py @@ -0,0 +1,128 @@ +""" +Task Manager for AITBC Agents +Handles task creation, assignment, and tracking +""" + +import uuid +from datetime import datetime, timedelta +from typing import Dict, Any, Optional, List +from enum import Enum + +class TaskStatus(Enum): + """Task status enumeration""" + PENDING = "pending" + IN_PROGRESS = "in_progress" + COMPLETED = "completed" + FAILED = "failed" + CANCELLED = "cancelled" + +class TaskPriority(Enum): + """Task priority enumeration""" + LOW = "low" + MEDIUM = "medium" + HIGH = "high" + URGENT = "urgent" + +class Task: + """Task representation""" + + def __init__( + self, + task_id: str, + title: str, + description: str, + assigned_to: str, + priority: TaskPriority = TaskPriority.MEDIUM, + created_by: Optional[str] = None + ): + self.task_id = task_id + self.title = title + self.description = description + self.assigned_to = assigned_to + self.priority = priority + self.created_by = created_by or assigned_to + self.status = TaskStatus.PENDING + self.created_at = datetime.utcnow() + self.updated_at = datetime.utcnow() + self.completed_at = None + self.result = None + self.error = None + +class TaskManager: + """Task manager for agent coordination""" + + def __init__(self): + self.tasks = {} + self.task_history = [] + + def create_task( + self, + title: str, + description: str, + assigned_to: str, + priority: TaskPriority = TaskPriority.MEDIUM, + created_by: Optional[str] = None + ) -> Task: + """Create a new task""" + task_id = str(uuid.uuid4()) + task = Task( + task_id=task_id, + title=title, + description=description, + assigned_to=assigned_to, + priority=priority, + created_by=created_by + ) + + self.tasks[task_id] = task + return task + + def get_task(self, task_id: str) -> Optional[Task]: + """Get a task by ID""" + return self.tasks.get(task_id) + + def update_task_status( + self, + task_id: str, + status: TaskStatus, + result: Optional[Dict[str, Any]] = None, + error: Optional[str] = None + ) -> bool: + """Update task status""" + task = self.get_task(task_id) + if not task: + return False + + task.status = status + task.updated_at = datetime.utcnow() + + if status == TaskStatus.COMPLETED: + task.completed_at = datetime.utcnow() + task.result = result + elif status == TaskStatus.FAILED: + task.error = error + + return True + + def get_tasks_by_agent(self, agent_id: str) -> List[Task]: + """Get all tasks assigned to an agent""" + return [ + task for task in self.tasks.values() + if task.assigned_to == agent_id + ] + + def get_tasks_by_status(self, status: TaskStatus) -> List[Task]: + """Get all tasks with a specific status""" + return [ + task for task in self.tasks.values() + if task.status == status + ] + + def get_overdue_tasks(self, hours: int = 24) -> List[Task]: + """Get tasks that are overdue""" + cutoff_time = datetime.utcnow() - timedelta(hours=hours) + return [ + task for task in self.tasks.values() + if task.status in [TaskStatus.PENDING, TaskStatus.IN_PROGRESS] and + task.created_at < cutoff_time + ] diff --git a/apps/blockchain-node/src/aitbc_chain/models.py b/apps/blockchain-node/src/aitbc_chain/models.py index 85132d15..a3efe3c9 100755 --- a/apps/blockchain-node/src/aitbc_chain/models.py +++ b/apps/blockchain-node/src/aitbc_chain/models.py @@ -25,7 +25,7 @@ def _validate_optional_hex(value: Optional[str], field_name: str) -> Optional[st class Block(SQLModel, table=True): __tablename__ = "block" - __table_args__ = (UniqueConstraint("chain_id", "height", name="uix_block_chain_height"),) + __table_args__ = (UniqueConstraint("chain_id", "height", name="uix_block_chain_height"), {"extend_existing": True}) id: Optional[int] = Field(default=None, primary_key=True) chain_id: str = Field(index=True) diff --git a/pyproject.toml b/pyproject.toml index db28bba0..3fdb21a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,7 +129,9 @@ dependencies = [ "pandas>=2.0.0", "aiohttp>=3.9.0", "fastapi>=0.111.0", - "uvicorn[standard]>=0.30.0" + "uvicorn[standard]>=0.30.0", + "slowapi>=0.1.0", + "pynacl>=1.5.0" ] classifiers = [ "Development Status :: 4 - Beta",