docs: add comprehensive contract testing, monitoring, and analytics workflow steps
All checks were successful
API Endpoint Tests / test-api-endpoints (push) Successful in 37s
Documentation Validation / validate-docs (push) Successful in 11s
Integration Tests / test-service-integration (push) Successful in 50s
Python Tests / test-python (push) Successful in 58s
Security Scanning / security-scan (push) Successful in 1m1s

📋 Workflow Enhancement:
• Add cross-node consensus testing with debugging reports (step 6)
• Add smart contract testing and service integration (step 7)
• Add enhanced contract and service testing with API structure validation (step 8)
• Add service health monitoring with quick, continuous, and alert modes (step 9)
• Add contract deployment and service integration testing (step 10)
• Add contract security and vulnerability testing with reports (step 11)
• Add
This commit is contained in:
aitbc1
2026-03-29 19:54:28 +02:00
parent df3f31b865
commit b5d7d6d982
23 changed files with 6799 additions and 1262 deletions

View File

@@ -0,0 +1,519 @@
"""
AITBC Agent Messaging Contract Implementation
This module implements on-chain messaging functionality for agents,
enabling forum-like communication between autonomous agents.
"""
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from enum import Enum
import json
import hashlib
from eth_account import Account
from eth_utils import to_checksum_address
class MessageType(Enum):
"""Types of messages agents can send"""
POST = "post"
REPLY = "reply"
ANNOUNCEMENT = "announcement"
QUESTION = "question"
ANSWER = "answer"
MODERATION = "moderation"
class MessageStatus(Enum):
"""Status of messages in the forum"""
ACTIVE = "active"
HIDDEN = "hidden"
DELETED = "deleted"
PINNED = "pinned"
@dataclass
class Message:
"""Represents a message in the agent forum"""
message_id: str
agent_id: str
agent_address: str
topic: str
content: str
message_type: MessageType
timestamp: datetime
parent_message_id: Optional[str] = None
reply_count: int = 0
upvotes: int = 0
downvotes: int = 0
status: MessageStatus = MessageStatus.ACTIVE
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class Topic:
"""Represents a forum topic"""
topic_id: str
title: str
description: str
creator_agent_id: str
created_at: datetime
message_count: int = 0
last_activity: datetime = field(default_factory=datetime.now)
tags: List[str] = field(default_factory=list)
is_pinned: bool = False
is_locked: bool = False
@dataclass
class AgentReputation:
"""Reputation system for agents"""
agent_id: str
message_count: int = 0
upvotes_received: int = 0
downvotes_received: int = 0
reputation_score: float = 0.0
trust_level: int = 1 # 1-5 trust levels
is_moderator: bool = False
is_banned: bool = False
ban_reason: Optional[str] = None
ban_expires: Optional[datetime] = None
class AgentMessagingContract:
"""Main contract for agent messaging functionality"""
def __init__(self):
self.messages: Dict[str, Message] = {}
self.topics: Dict[str, Topic] = {}
self.agent_reputations: Dict[str, AgentReputation] = {}
self.moderation_log: List[Dict[str, Any]] = []
def create_topic(self, agent_id: str, agent_address: str, title: str,
description: str, tags: List[str] = None) -> Dict[str, Any]:
"""Create a new forum topic"""
# Check if agent is banned
if self._is_agent_banned(agent_id):
return {
"success": False,
"error": "Agent is banned from posting",
"error_code": "AGENT_BANNED"
}
# Generate topic ID
topic_id = f"topic_{hashlib.sha256(f'{agent_id}_{title}_{datetime.now()}'.encode()).hexdigest()[:16]}"
# Create topic
topic = Topic(
topic_id=topic_id,
title=title,
description=description,
creator_agent_id=agent_id,
created_at=datetime.now(),
tags=tags or []
)
self.topics[topic_id] = topic
# Update agent reputation
self._update_agent_reputation(agent_id, message_count=1)
return {
"success": True,
"topic_id": topic_id,
"topic": self._topic_to_dict(topic)
}
def post_message(self, agent_id: str, agent_address: str, topic_id: str,
content: str, message_type: str = "post",
parent_message_id: str = None) -> Dict[str, Any]:
"""Post a message to a forum topic"""
# Validate inputs
if not self._validate_agent(agent_id, agent_address):
return {
"success": False,
"error": "Invalid agent credentials",
"error_code": "INVALID_AGENT"
}
if self._is_agent_banned(agent_id):
return {
"success": False,
"error": "Agent is banned from posting",
"error_code": "AGENT_BANNED"
}
if topic_id not in self.topics:
return {
"success": False,
"error": "Topic not found",
"error_code": "TOPIC_NOT_FOUND"
}
if self.topics[topic_id].is_locked:
return {
"success": False,
"error": "Topic is locked",
"error_code": "TOPIC_LOCKED"
}
# Validate message type
try:
msg_type = MessageType(message_type)
except ValueError:
return {
"success": False,
"error": "Invalid message type",
"error_code": "INVALID_MESSAGE_TYPE"
}
# Generate message ID
message_id = f"msg_{hashlib.sha256(f'{agent_id}_{topic_id}_{content}_{datetime.now()}'.encode()).hexdigest()[:16]}"
# Create message
message = Message(
message_id=message_id,
agent_id=agent_id,
agent_address=agent_address,
topic=topic_id,
content=content,
message_type=msg_type,
timestamp=datetime.now(),
parent_message_id=parent_message_id
)
self.messages[message_id] = message
# Update topic
self.topics[topic_id].message_count += 1
self.topics[topic_id].last_activity = datetime.now()
# Update parent message if this is a reply
if parent_message_id and parent_message_id in self.messages:
self.messages[parent_message_id].reply_count += 1
# Update agent reputation
self._update_agent_reputation(agent_id, message_count=1)
return {
"success": True,
"message_id": message_id,
"message": self._message_to_dict(message)
}
def get_messages(self, topic_id: str, limit: int = 50, offset: int = 0,
sort_by: str = "timestamp") -> Dict[str, Any]:
"""Get messages from a topic"""
if topic_id not in self.topics:
return {
"success": False,
"error": "Topic not found",
"error_code": "TOPIC_NOT_FOUND"
}
# Get all messages for this topic
topic_messages = [
msg for msg in self.messages.values()
if msg.topic == topic_id and msg.status == MessageStatus.ACTIVE
]
# Sort messages
if sort_by == "timestamp":
topic_messages.sort(key=lambda x: x.timestamp, reverse=True)
elif sort_by == "upvotes":
topic_messages.sort(key=lambda x: x.upvotes, reverse=True)
elif sort_by == "replies":
topic_messages.sort(key=lambda x: x.reply_count, reverse=True)
# Apply pagination
total_messages = len(topic_messages)
paginated_messages = topic_messages[offset:offset + limit]
return {
"success": True,
"messages": [self._message_to_dict(msg) for msg in paginated_messages],
"total_messages": total_messages,
"topic": self._topic_to_dict(self.topics[topic_id])
}
def get_topics(self, limit: int = 50, offset: int = 0,
sort_by: str = "last_activity") -> Dict[str, Any]:
"""Get list of forum topics"""
# Sort topics
topic_list = list(self.topics.values())
if sort_by == "last_activity":
topic_list.sort(key=lambda x: x.last_activity, reverse=True)
elif sort_by == "created_at":
topic_list.sort(key=lambda x: x.created_at, reverse=True)
elif sort_by == "message_count":
topic_list.sort(key=lambda x: x.message_count, reverse=True)
# Apply pagination
total_topics = len(topic_list)
paginated_topics = topic_list[offset:offset + limit]
return {
"success": True,
"topics": [self._topic_to_dict(topic) for topic in paginated_topics],
"total_topics": total_topics
}
def vote_message(self, agent_id: str, agent_address: str, message_id: str,
vote_type: str) -> Dict[str, Any]:
"""Vote on a message (upvote/downvote)"""
# Validate inputs
if not self._validate_agent(agent_id, agent_address):
return {
"success": False,
"error": "Invalid agent credentials",
"error_code": "INVALID_AGENT"
}
if message_id not in self.messages:
return {
"success": False,
"error": "Message not found",
"error_code": "MESSAGE_NOT_FOUND"
}
if vote_type not in ["upvote", "downvote"]:
return {
"success": False,
"error": "Invalid vote type",
"error_code": "INVALID_VOTE_TYPE"
}
message = self.messages[message_id]
# Update vote counts
if vote_type == "upvote":
message.upvotes += 1
else:
message.downvotes += 1
# Update message author reputation
self._update_agent_reputation(
message.agent_id,
upvotes_received=message.upvotes,
downvotes_received=message.downvotes
)
return {
"success": True,
"message_id": message_id,
"upvotes": message.upvotes,
"downvotes": message.downvotes
}
def moderate_message(self, moderator_agent_id: str, moderator_address: str,
message_id: str, action: str, reason: str = "") -> Dict[str, Any]:
"""Moderate a message (hide, delete, pin)"""
# Validate moderator
if not self._is_moderator(moderator_agent_id):
return {
"success": False,
"error": "Insufficient permissions",
"error_code": "INSUFFICIENT_PERMISSIONS"
}
if message_id not in self.messages:
return {
"success": False,
"error": "Message not found",
"error_code": "MESSAGE_NOT_FOUND"
}
message = self.messages[message_id]
# Apply moderation action
if action == "hide":
message.status = MessageStatus.HIDDEN
elif action == "delete":
message.status = MessageStatus.DELETED
elif action == "pin":
message.status = MessageStatus.PINNED
elif action == "unpin":
message.status = MessageStatus.ACTIVE
else:
return {
"success": False,
"error": "Invalid moderation action",
"error_code": "INVALID_ACTION"
}
# Log moderation action
self.moderation_log.append({
"timestamp": datetime.now(),
"moderator_agent_id": moderator_agent_id,
"message_id": message_id,
"action": action,
"reason": reason
})
return {
"success": True,
"message_id": message_id,
"status": message.status.value
}
def get_agent_reputation(self, agent_id: str) -> Dict[str, Any]:
"""Get an agent's reputation information"""
if agent_id not in self.agent_reputations:
return {
"success": False,
"error": "Agent not found",
"error_code": "AGENT_NOT_FOUND"
}
reputation = self.agent_reputations[agent_id]
return {
"success": True,
"agent_id": agent_id,
"reputation": self._reputation_to_dict(reputation)
}
def search_messages(self, query: str, limit: int = 50) -> Dict[str, Any]:
"""Search messages by content"""
# Simple text search (in production, use proper search engine)
query_lower = query.lower()
matching_messages = []
for message in self.messages.values():
if (message.status == MessageStatus.ACTIVE and
query_lower in message.content.lower()):
matching_messages.append(message)
# Sort by timestamp (most recent first)
matching_messages.sort(key=lambda x: x.timestamp, reverse=True)
# Limit results
limited_messages = matching_messages[:limit]
return {
"success": True,
"query": query,
"messages": [self._message_to_dict(msg) for msg in limited_messages],
"total_matches": len(matching_messages)
}
def _validate_agent(self, agent_id: str, agent_address: str) -> bool:
"""Validate agent credentials"""
# In a real implementation, this would verify the agent's signature
# For now, we'll do basic validation
return bool(agent_id and agent_address)
def _is_agent_banned(self, agent_id: str) -> bool:
"""Check if an agent is banned"""
if agent_id not in self.agent_reputations:
return False
reputation = self.agent_reputations[agent_id]
if reputation.is_banned:
# Check if ban has expired
if reputation.ban_expires and datetime.now() > reputation.ban_expires:
reputation.is_banned = False
reputation.ban_expires = None
reputation.ban_reason = None
return False
return True
return False
def _is_moderator(self, agent_id: str) -> bool:
"""Check if an agent is a moderator"""
if agent_id not in self.agent_reputations:
return False
return self.agent_reputations[agent_id].is_moderator
def _update_agent_reputation(self, agent_id: str, message_count: int = 0,
upvotes_received: int = 0, downvotes_received: int = 0):
"""Update agent reputation"""
if agent_id not in self.agent_reputations:
self.agent_reputations[agent_id] = AgentReputation(agent_id=agent_id)
reputation = self.agent_reputations[agent_id]
if message_count > 0:
reputation.message_count += message_count
if upvotes_received > 0:
reputation.upvotes_received += upvotes_received
if downvotes_received > 0:
reputation.downvotes_received += downvotes_received
# Calculate reputation score
total_votes = reputation.upvotes_received + reputation.downvotes_received
if total_votes > 0:
reputation.reputation_score = (reputation.upvotes_received - reputation.downvotes_received) / total_votes
# Update trust level based on reputation score
if reputation.reputation_score >= 0.8:
reputation.trust_level = 5
elif reputation.reputation_score >= 0.6:
reputation.trust_level = 4
elif reputation.reputation_score >= 0.4:
reputation.trust_level = 3
elif reputation.reputation_score >= 0.2:
reputation.trust_level = 2
else:
reputation.trust_level = 1
def _message_to_dict(self, message: Message) -> Dict[str, Any]:
"""Convert message to dictionary"""
return {
"message_id": message.message_id,
"agent_id": message.agent_id,
"agent_address": message.agent_address,
"topic": message.topic,
"content": message.content,
"message_type": message.message_type.value,
"timestamp": message.timestamp.isoformat(),
"parent_message_id": message.parent_message_id,
"reply_count": message.reply_count,
"upvotes": message.upvotes,
"downvotes": message.downvotes,
"status": message.status.value,
"metadata": message.metadata
}
def _topic_to_dict(self, topic: Topic) -> Dict[str, Any]:
"""Convert topic to dictionary"""
return {
"topic_id": topic.topic_id,
"title": topic.title,
"description": topic.description,
"creator_agent_id": topic.creator_agent_id,
"created_at": topic.created_at.isoformat(),
"message_count": topic.message_count,
"last_activity": topic.last_activity.isoformat(),
"tags": topic.tags,
"is_pinned": topic.is_pinned,
"is_locked": topic.is_locked
}
def _reputation_to_dict(self, reputation: AgentReputation) -> Dict[str, Any]:
"""Convert reputation to dictionary"""
return {
"agent_id": reputation.agent_id,
"message_count": reputation.message_count,
"upvotes_received": reputation.upvotes_received,
"downvotes_received": reputation.downvotes_received,
"reputation_score": reputation.reputation_score,
"trust_level": reputation.trust_level,
"is_moderator": reputation.is_moderator,
"is_banned": reputation.is_banned,
"ban_reason": reputation.ban_reason,
"ban_expires": reputation.ban_expires.isoformat() if reputation.ban_expires else None
}
# Global contract instance
messaging_contract = AgentMessagingContract()

View File

@@ -0,0 +1,11 @@
"""Contract Service Module"""
from typing import Dict, Any
import hashlib
import time
class ContractService:
@staticmethod
def list_contracts() -> Dict[str, Any]:
return {"contracts": [{"address": "0xguardian_001", "name": "Guardian Contract", "status": "deployed", "functions": ["storeValue", "getValue", "setGuardian"]}], "total": 1}
contract_service = ContractService()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,754 @@
"""
AITBC Agent Communication SDK Extension
This module extends the Agent Identity SDK with communication methods
for forum-like agent interactions using the blockchain messaging contract.
"""
import asyncio
import json
from datetime import datetime
from typing import Dict, List, Optional, Any, Union
from dataclasses import dataclass
import hashlib
import logging
from .client import AgentIdentityClient
from .models import AgentIdentity, AgentWallet
logger = logging.getLogger(__name__)
@dataclass
class ForumTopic:
"""Forum topic data structure"""
topic_id: str
title: str
description: str
creator_agent_id: str
created_at: datetime
message_count: int
last_activity: datetime
tags: List[str]
is_pinned: bool
is_locked: bool
@dataclass
class ForumMessage:
"""Forum message data structure"""
message_id: str
agent_id: str
agent_address: str
topic: str
content: str
message_type: str
timestamp: datetime
parent_message_id: Optional[str]
reply_count: int
upvotes: int
downvotes: int
status: str
metadata: Dict[str, Any]
@dataclass
class AgentReputation:
"""Agent reputation data structure"""
agent_id: str
message_count: int
upvotes_received: int
downvotes_received: int
reputation_score: float
trust_level: int
is_moderator: bool
is_banned: bool
ban_reason: Optional[str]
ban_expires: Optional[datetime]
class AgentCommunicationClient:
"""Extended client for agent communication functionality"""
def __init__(self, base_url: str, agent_id: str, private_key: str = None):
"""
Initialize the communication client
Args:
base_url: Base URL for the coordinator API
agent_id: Agent identifier
private_key: Agent's private key for signing messages
"""
self.base_url = base_url
self.agent_id = agent_id
self.private_key = private_key
self.identity_client = AgentIdentityClient(base_url, agent_id, private_key)
async def create_forum_topic(self, title: str, description: str,
tags: List[str] = None) -> Dict[str, Any]:
"""
Create a new forum topic
Args:
title: Topic title
description: Topic description
tags: Optional list of tags
Returns:
Topic creation result
"""
try:
# Verify agent identity
identity = await self.identity_client.get_identity()
if not identity:
return {
"success": False,
"error": "Agent identity not found",
"error_code": "IDENTITY_NOT_FOUND"
}
# Get agent address
agent_address = identity.wallets[0].address if identity.wallets else None
if not agent_address:
return {
"success": False,
"error": "No wallet found for agent",
"error_code": "NO_WALLET_FOUND"
}
# Create topic via blockchain contract
topic_data = {
"agent_id": self.agent_id,
"agent_address": agent_address,
"title": title,
"description": description,
"tags": tags or []
}
# This would call the blockchain contract
result = await self._call_messaging_contract("create_topic", topic_data)
return result
except Exception as e:
logger.error(f"Error creating forum topic: {e}")
return {
"success": False,
"error": str(e),
"error_code": "TOPIC_CREATION_FAILED"
}
async def post_message(self, topic_id: str, content: str,
message_type: str = "post",
parent_message_id: str = None) -> Dict[str, Any]:
"""
Post a message to a forum topic
Args:
topic_id: Target topic ID
content: Message content
message_type: Type of message (post, reply, question, etc.)
parent_message_id: Parent message ID for replies
Returns:
Message posting result
"""
try:
# Verify agent identity
identity = await self.identity_client.get_identity()
if not identity:
return {
"success": False,
"error": "Agent identity not found",
"error_code": "IDENTITY_NOT_FOUND"
}
# Get agent address
agent_address = identity.wallets[0].address if identity.wallets else None
if not agent_address:
return {
"success": False,
"error": "No wallet found for agent",
"error_code": "NO_WALLET_FOUND"
}
# Post message via blockchain contract
message_data = {
"agent_id": self.agent_id,
"agent_address": agent_address,
"topic_id": topic_id,
"content": content,
"message_type": message_type,
"parent_message_id": parent_message_id
}
result = await self._call_messaging_contract("post_message", message_data)
return result
except Exception as e:
logger.error(f"Error posting message: {e}")
return {
"success": False,
"error": str(e),
"error_code": "MESSAGE_POSTING_FAILED"
}
async def get_topic_messages(self, topic_id: str, limit: int = 50,
offset: int = 0, sort_by: str = "timestamp") -> Dict[str, Any]:
"""
Get messages from a forum topic
Args:
topic_id: Topic ID
limit: Maximum number of messages to return
offset: Offset for pagination
sort_by: Sort method (timestamp, upvotes, replies)
Returns:
Messages and topic information
"""
try:
params = {
"topic_id": topic_id,
"limit": limit,
"offset": offset,
"sort_by": sort_by
}
result = await self._call_messaging_contract("get_messages", params)
return result
except Exception as e:
logger.error(f"Error getting topic messages: {e}")
return {
"success": False,
"error": str(e),
"error_code": "GET_MESSAGES_FAILED"
}
async def get_forum_topics(self, limit: int = 50, offset: int = 0,
sort_by: str = "last_activity") -> Dict[str, Any]:
"""
Get list of forum topics
Args:
limit: Maximum number of topics to return
offset: Offset for pagination
sort_by: Sort method (last_activity, created_at, message_count)
Returns:
List of topics
"""
try:
params = {
"limit": limit,
"offset": offset,
"sort_by": sort_by
}
result = await self._call_messaging_contract("get_topics", params)
return result
except Exception as e:
logger.error(f"Error getting forum topics: {e}")
return {
"success": False,
"error": str(e),
"error_code": "GET_TOPICS_FAILED"
}
async def vote_message(self, message_id: str, vote_type: str) -> Dict[str, Any]:
"""
Vote on a message (upvote/downvote)
Args:
message_id: Message ID to vote on
vote_type: Type of vote ("upvote" or "downvote")
Returns:
Vote result
"""
try:
# Verify agent identity
identity = await self.identity_client.get_identity()
if not identity:
return {
"success": False,
"error": "Agent identity not found",
"error_code": "IDENTITY_NOT_FOUND"
}
# Get agent address
agent_address = identity.wallets[0].address if identity.wallets else None
if not agent_address:
return {
"success": False,
"error": "No wallet found for agent",
"error_code": "NO_WALLET_FOUND"
}
vote_data = {
"agent_id": self.agent_id,
"agent_address": agent_address,
"message_id": message_id,
"vote_type": vote_type
}
result = await self._call_messaging_contract("vote_message", vote_data)
return result
except Exception as e:
logger.error(f"Error voting on message: {e}")
return {
"success": False,
"error": str(e),
"error_code": "VOTE_FAILED"
}
async def reply_to_message(self, message_id: str, content: str) -> Dict[str, Any]:
"""
Reply to a message
Args:
message_id: Parent message ID
content: Reply content
Returns:
Reply posting result
"""
try:
# Get the original message to find the topic
original_message = await self._get_message_details(message_id)
if not original_message.get("success"):
return original_message
topic_id = original_message["message"]["topic"]
# Post as a reply
return await self.post_message(
topic_id=topic_id,
content=content,
message_type="reply",
parent_message_id=message_id
)
except Exception as e:
logger.error(f"Error replying to message: {e}")
return {
"success": False,
"error": str(e),
"error_code": "REPLY_FAILED"
}
async def search_messages(self, query: str, limit: int = 50) -> Dict[str, Any]:
"""
Search messages by content
Args:
query: Search query
limit: Maximum number of results
Returns:
Search results
"""
try:
params = {
"query": query,
"limit": limit
}
result = await self._call_messaging_contract("search_messages", params)
return result
except Exception as e:
logger.error(f"Error searching messages: {e}")
return {
"success": False,
"error": str(e),
"error_code": "SEARCH_FAILED"
}
async def get_agent_reputation(self, agent_id: str = None) -> Dict[str, Any]:
"""
Get agent reputation information
Args:
agent_id: Agent ID (defaults to current agent)
Returns:
Reputation information
"""
try:
target_agent_id = agent_id or self.agent_id
result = await self._call_messaging_contract("get_agent_reputation", {
"agent_id": target_agent_id
})
return result
except Exception as e:
logger.error(f"Error getting agent reputation: {e}")
return {
"success": False,
"error": str(e),
"error_code": "GET_REPUTATION_FAILED"
}
async def moderate_message(self, message_id: str, action: str,
reason: str = "") -> Dict[str, Any]:
"""
Moderate a message (moderator only)
Args:
message_id: Message ID to moderate
action: Action to take (hide, delete, pin, unpin)
reason: Reason for moderation
Returns:
Moderation result
"""
try:
# Verify agent is a moderator
reputation = await self.get_agent_reputation()
if not reputation.get("success"):
return reputation
if not reputation["reputation"].get("is_moderator", False):
return {
"success": False,
"error": "Insufficient permissions",
"error_code": "INSUFFICIENT_PERMISSIONS"
}
# Get agent address
identity = await self.identity_client.get_identity()
agent_address = identity.wallets[0].address if identity.wallets else None
moderation_data = {
"moderator_agent_id": self.agent_id,
"moderator_address": agent_address,
"message_id": message_id,
"action": action,
"reason": reason
}
result = await self._call_messaging_contract("moderate_message", moderation_data)
return result
except Exception as e:
logger.error(f"Error moderating message: {e}")
return {
"success": False,
"error": str(e),
"error_code": "MODERATION_FAILED"
}
async def create_announcement(self, content: str, topic_id: str = None) -> Dict[str, Any]:
"""
Create an announcement message
Args:
content: Announcement content
topic_id: Optional topic ID (creates new topic if not provided)
Returns:
Announcement creation result
"""
try:
if topic_id:
# Post to existing topic
return await self.post_message(topic_id, content, "announcement")
else:
# Create new topic for announcement
title = f"Announcement from {self.agent_id}"
description = "Official announcement"
topic_result = await self.create_forum_topic(title, description, ["announcement"])
if not topic_result.get("success"):
return topic_result
# Post announcement to new topic
return await self.post_message(topic_result["topic_id"], content, "announcement")
except Exception as e:
logger.error(f"Error creating announcement: {e}")
return {
"success": False,
"error": str(e),
"error_code": "ANNOUNCEMENT_FAILED"
}
async def ask_question(self, topic_id: str, question: str) -> Dict[str, Any]:
"""
Ask a question in a forum topic
Args:
topic_id: Topic ID
question: Question content
Returns:
Question posting result
"""
return await self.post_message(topic_id, question, "question")
async def answer_question(self, message_id: str, answer: str) -> Dict[str, Any]:
"""
Answer a question
Args:
message_id: Question message ID
answer: Answer content
Returns:
Answer posting result
"""
try:
# Get the original question to find the topic
original_message = await self._get_message_details(message_id)
if not original_message.get("success"):
return original_message
topic_id = original_message["message"]["topic"]
# Post as an answer
return await self.post_message(
topic_id=topic_id,
content=answer,
message_type="answer",
parent_message_id=message_id
)
except Exception as e:
logger.error(f"Error answering question: {e}")
return {
"success": False,
"error": str(e),
"error_code": "ANSWER_FAILED"
}
async def _call_messaging_contract(self, method: str, params: Dict[str, Any]) -> Dict[str, Any]:
"""
Call the messaging contract method
Args:
method: Contract method name
params: Method parameters
Returns:
Contract call result
"""
# This would make an actual call to the blockchain contract
# For now, we'll simulate the call
try:
# In a real implementation, this would:
# 1. Sign the transaction
# 2. Call the smart contract
# 3. Wait for confirmation
# 4. Return the result
# For simulation, we'll return a mock response
if method == "create_topic":
topic_id = f"topic_{hashlib.sha256(f'{params.get(\"agent_id\")}_{params.get(\"title\")}_{datetime.now()}'.encode()).hexdigest()[:16]}"
return {
"success": True,
"topic_id": topic_id,
"topic": {
"topic_id": topic_id,
"title": params["title"],
"description": params["description"],
"creator_agent_id": params["agent_id"],
"created_at": datetime.now().isoformat(),
"message_count": 0,
"last_activity": datetime.now().isoformat(),
"tags": params.get("tags", []),
"is_pinned": False,
"is_locked": False
}
}
elif method == "post_message":
message_id = f"msg_{hashlib.sha256(f'{params.get(\"agent_id\")}_{params.get(\"topic_id\")}_{params.get(\"content\")}_{datetime.now()}'.encode()).hexdigest()[:16]}"
return {
"success": True,
"message_id": message_id,
"message": {
"message_id": message_id,
"agent_id": params["agent_id"],
"agent_address": params["agent_address"],
"topic": params["topic_id"],
"content": params["content"],
"message_type": params["message_type"],
"timestamp": datetime.now().isoformat(),
"parent_message_id": params.get("parent_message_id"),
"reply_count": 0,
"upvotes": 0,
"downvotes": 0,
"status": "active",
"metadata": {}
}
}
elif method == "get_messages":
return {
"success": True,
"messages": [],
"total_messages": 0,
"topic": {
"topic_id": params["topic_id"],
"title": "Sample Topic",
"description": "Sample description"
}
}
elif method == "get_topics":
return {
"success": True,
"topics": [],
"total_topics": 0
}
elif method == "vote_message":
return {
"success": True,
"message_id": params["message_id"],
"upvotes": 1,
"downvotes": 0
}
elif method == "search_messages":
return {
"success": True,
"query": params["query"],
"messages": [],
"total_matches": 0
}
elif method == "get_agent_reputation":
return {
"success": True,
"agent_id": params["agent_id"],
"reputation": {
"agent_id": params["agent_id"],
"message_count": 0,
"upvotes_received": 0,
"downvotes_received": 0,
"reputation_score": 0.0,
"trust_level": 1,
"is_moderator": False,
"is_banned": False,
"ban_reason": None,
"ban_expires": None
}
}
elif method == "moderate_message":
return {
"success": True,
"message_id": params["message_id"],
"status": params["action"]
}
else:
return {
"success": False,
"error": f"Unknown method: {method}",
"error_code": "UNKNOWN_METHOD"
}
except Exception as e:
logger.error(f"Error calling messaging contract: {e}")
return {
"success": False,
"error": str(e),
"error_code": "CONTRACT_CALL_FAILED"
}
async def _get_message_details(self, message_id: str) -> Dict[str, Any]:
"""
Get details of a specific message
Args:
message_id: Message ID
Returns:
Message details
"""
try:
# This would search for the message in the contract
# For now, we'll return a mock response
return {
"success": True,
"message": {
"message_id": message_id,
"topic": "sample_topic_id",
"agent_id": "sample_agent_id",
"content": "Sample message content",
"timestamp": datetime.now().isoformat()
}
}
except Exception as e:
logger.error(f"Error getting message details: {e}")
return {
"success": False,
"error": str(e),
"error_code": "GET_MESSAGE_FAILED"
}
# Convenience functions for common operations
async def create_agent_forum_client(base_url: str, agent_id: str,
private_key: str) -> AgentCommunicationClient:
"""
Create an agent forum client
Args:
base_url: Base URL for the coordinator API
agent_id: Agent identifier
private_key: Agent's private key
Returns:
Configured communication client
"""
return AgentCommunicationClient(base_url, agent_id, private_key)
async def start_forum_discussion(base_url: str, agent_id: str, private_key: str,
title: str, description: str, initial_message: str) -> Dict[str, Any]:
"""
Start a new forum discussion
Args:
base_url: Base URL for the coordinator API
agent_id: Agent identifier
private_key: Agent's private key
title: Discussion title
description: Discussion description
initial_message: Initial message content
Returns:
Discussion creation result
"""
client = await create_agent_forum_client(base_url, agent_id, private_key)
# Create topic
topic_result = await client.create_forum_topic(title, description)
if not topic_result.get("success"):
return topic_result
# Post initial message
message_result = await client.post_message(
topic_result["topic_id"],
initial_message,
"post"
)
return {
"success": message_result.get("success", False),
"topic_id": topic_result["topic_id"],
"message_id": message_result.get("message_id"),
"topic": topic_result.get("topic"),
"message": message_result.get("message")
}