docs: add code quality and type checking workflows to master index
Some checks failed
Documentation Validation / validate-docs (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
API Endpoint Tests / test-api-endpoints (push) Has been cancelled
CLI Tests / test-cli (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Package Tests / test-python-packages (map[name:aitbc-agent-sdk path:packages/py/aitbc-agent-sdk]) (push) Has been cancelled
Package Tests / test-python-packages (map[name:aitbc-core path:packages/py/aitbc-core]) (push) Has been cancelled
Package Tests / test-python-packages (map[name:aitbc-crypto path:packages/py/aitbc-crypto]) (push) Has been cancelled
Package Tests / test-python-packages (map[name:aitbc-sdk path:packages/py/aitbc-sdk]) (push) Has been cancelled
Package Tests / test-javascript-packages (map[name:aitbc-sdk-js path:packages/js/aitbc-sdk]) (push) Has been cancelled
Package Tests / test-javascript-packages (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
Systemd Sync / sync-systemd (push) Has been cancelled

- Add Code Quality Module section with pre-commit hooks and quality checks
- Add Type Checking CI/CD Module section with MyPy workflow and coverage
- Update README with code quality achievements and project structure
- Migrate FastAPI apps from deprecated on_event to lifespan context manager
- Update pyproject.toml files to reference consolidated dependencies
- Remove unused app.py import in coordinator-api
- Add type hints to agent
This commit is contained in:
aitbc
2026-03-31 21:45:43 +02:00
parent 26592ddf55
commit 9db720add8
308 changed files with 34194 additions and 34575 deletions

View File

@@ -3,235 +3,236 @@ Cross-Chain Reputation Aggregator
Aggregates reputation data from multiple blockchains and normalizes scores
"""
import asyncio
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Set
from uuid import uuid4
import json
import logging
from datetime import datetime
from typing import Any
logger = logging.getLogger(__name__)
from sqlmodel import Session, select, update, delete, func
from sqlalchemy.exc import SQLAlchemyError
from sqlmodel import Session, select
from ..domain.reputation import AgentReputation, ReputationEvent
from ..domain.cross_chain_reputation import (
CrossChainReputationAggregation, CrossChainReputationEvent,
CrossChainReputationConfig, ReputationMetrics
CrossChainReputationAggregation,
CrossChainReputationConfig,
)
from ..domain.reputation import AgentReputation, ReputationEvent
class CrossChainReputationAggregator:
"""Aggregates reputation data from multiple blockchains"""
def __init__(self, session: Session, blockchain_clients: Optional[Dict[int, Any]] = None):
def __init__(self, session: Session, blockchain_clients: dict[int, Any] | None = None):
self.session = session
self.blockchain_clients = blockchain_clients or {}
async def collect_chain_reputation_data(self, chain_id: int) -> List[Dict[str, Any]]:
async def collect_chain_reputation_data(self, chain_id: int) -> list[dict[str, Any]]:
"""Collect reputation data from a specific blockchain"""
try:
# Get all reputations for the chain
stmt = select(AgentReputation).where(
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, 'chain_id') else True
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, "chain_id") else True
)
# Handle case where reputation doesn't have chain_id
if not hasattr(AgentReputation, 'chain_id'):
if not hasattr(AgentReputation, "chain_id"):
# For now, return all reputations (assume they're on the primary chain)
stmt = select(AgentReputation)
reputations = self.session.exec(stmt).all()
chain_data = []
for reputation in reputations:
chain_data.append({
'agent_id': reputation.agent_id,
'trust_score': reputation.trust_score,
'reputation_level': reputation.reputation_level,
'total_transactions': getattr(reputation, 'transaction_count', 0),
'success_rate': getattr(reputation, 'success_rate', 0.0),
'dispute_count': getattr(reputation, 'dispute_count', 0),
'last_updated': reputation.updated_at,
'chain_id': getattr(reputation, 'chain_id', chain_id)
})
chain_data.append(
{
"agent_id": reputation.agent_id,
"trust_score": reputation.trust_score,
"reputation_level": reputation.reputation_level,
"total_transactions": getattr(reputation, "transaction_count", 0),
"success_rate": getattr(reputation, "success_rate", 0.0),
"dispute_count": getattr(reputation, "dispute_count", 0),
"last_updated": reputation.updated_at,
"chain_id": getattr(reputation, "chain_id", chain_id),
}
)
return chain_data
except Exception as e:
logger.error(f"Error collecting reputation data for chain {chain_id}: {e}")
return []
async def normalize_reputation_scores(self, scores: Dict[int, float]) -> float:
async def normalize_reputation_scores(self, scores: dict[int, float]) -> float:
"""Normalize reputation scores across chains"""
try:
if not scores:
return 0.0
# Get chain configurations
chain_configs = {}
for chain_id in scores.keys():
config = await self._get_chain_config(chain_id)
chain_configs[chain_id] = config
# Apply chain-specific normalization
normalized_scores = {}
total_weight = 0.0
weighted_sum = 0.0
for chain_id, score in scores.items():
config = chain_configs.get(chain_id)
if config and config.is_active:
# Apply chain weight
weight = config.chain_weight
normalized_score = score * weight
normalized_scores[chain_id] = normalized_score
total_weight += weight
weighted_sum += normalized_score
# Calculate final normalized score
if total_weight > 0:
final_score = weighted_sum / total_weight
else:
# If no valid configurations, use simple average
final_score = sum(scores.values()) / len(scores)
return max(0.0, min(1.0, final_score))
except Exception as e:
logger.error(f"Error normalizing reputation scores: {e}")
return 0.0
async def apply_chain_weighting(self, scores: Dict[int, float]) -> Dict[int, float]:
async def apply_chain_weighting(self, scores: dict[int, float]) -> dict[int, float]:
"""Apply chain-specific weighting to reputation scores"""
try:
weighted_scores = {}
for chain_id, score in scores.items():
config = await self._get_chain_config(chain_id)
if config and config.is_active:
weight = config.chain_weight
weighted_scores[chain_id] = score * weight
else:
# Default weight if no config
weighted_scores[chain_id] = score
return weighted_scores
except Exception as e:
logger.error(f"Error applying chain weighting: {e}")
return scores
async def detect_reputation_anomalies(self, agent_id: str) -> List[Dict[str, Any]]:
async def detect_reputation_anomalies(self, agent_id: str) -> list[dict[str, Any]]:
"""Detect reputation anomalies across chains"""
try:
anomalies = []
# Get cross-chain aggregation
stmt = select(CrossChainReputationAggregation).where(
CrossChainReputationAggregation.agent_id == agent_id
)
stmt = select(CrossChainReputationAggregation).where(CrossChainReputationAggregation.agent_id == agent_id)
aggregation = self.session.exec(stmt).first()
if not aggregation:
return anomalies
# Check for consistency anomalies
if aggregation.consistency_score < 0.7:
anomalies.append({
'agent_id': agent_id,
'anomaly_type': 'low_consistency',
'detected_at': datetime.utcnow(),
'description': f"Low consistency score: {aggregation.consistency_score:.2f}",
'severity': 'high' if aggregation.consistency_score < 0.5 else 'medium',
'consistency_score': aggregation.consistency_score,
'score_variance': aggregation.score_variance,
'score_range': aggregation.score_range
})
anomalies.append(
{
"agent_id": agent_id,
"anomaly_type": "low_consistency",
"detected_at": datetime.utcnow(),
"description": f"Low consistency score: {aggregation.consistency_score:.2f}",
"severity": "high" if aggregation.consistency_score < 0.5 else "medium",
"consistency_score": aggregation.consistency_score,
"score_variance": aggregation.score_variance,
"score_range": aggregation.score_range,
}
)
# Check for score variance anomalies
if aggregation.score_variance > 0.25:
anomalies.append({
'agent_id': agent_id,
'anomaly_type': 'high_variance',
'detected_at': datetime.utcnow(),
'description': f"High score variance: {aggregation.score_variance:.2f}",
'severity': 'high' if aggregation.score_variance > 0.5 else 'medium',
'score_variance': aggregation.score_variance,
'score_range': aggregation.score_range,
'chain_scores': aggregation.chain_scores
})
anomalies.append(
{
"agent_id": agent_id,
"anomaly_type": "high_variance",
"detected_at": datetime.utcnow(),
"description": f"High score variance: {aggregation.score_variance:.2f}",
"severity": "high" if aggregation.score_variance > 0.5 else "medium",
"score_variance": aggregation.score_variance,
"score_range": aggregation.score_range,
"chain_scores": aggregation.chain_scores,
}
)
# Check for missing chain data
expected_chains = await self._get_active_chain_ids()
missing_chains = set(expected_chains) - set(aggregation.active_chains)
if missing_chains:
anomalies.append({
'agent_id': agent_id,
'anomaly_type': 'missing_chain_data',
'detected_at': datetime.utcnow(),
'description': f"Missing data for chains: {list(missing_chains)}",
'severity': 'medium',
'missing_chains': list(missing_chains),
'active_chains': aggregation.active_chains
})
anomalies.append(
{
"agent_id": agent_id,
"anomaly_type": "missing_chain_data",
"detected_at": datetime.utcnow(),
"description": f"Missing data for chains: {list(missing_chains)}",
"severity": "medium",
"missing_chains": list(missing_chains),
"active_chains": aggregation.active_chains,
}
)
return anomalies
except Exception as e:
logger.error(f"Error detecting reputation anomalies for agent {agent_id}: {e}")
return []
async def batch_update_reputations(self, updates: List[Dict[str, Any]]) -> Dict[str, bool]:
async def batch_update_reputations(self, updates: list[dict[str, Any]]) -> dict[str, bool]:
"""Batch update reputation scores for multiple agents"""
try:
results = {}
for update in updates:
agent_id = update['agent_id']
chain_id = update.get('chain_id', 1)
new_score = update['score']
agent_id = update["agent_id"]
chain_id = update.get("chain_id", 1)
new_score = update["score"]
try:
# Get existing reputation
stmt = select(AgentReputation).where(
AgentReputation.agent_id == agent_id,
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, 'chain_id') else True
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, "chain_id") else True,
)
if not hasattr(AgentReputation, 'chain_id'):
if not hasattr(AgentReputation, "chain_id"):
stmt = select(AgentReputation).where(AgentReputation.agent_id == agent_id)
reputation = self.session.exec(stmt).first()
if reputation:
# Update reputation
reputation.trust_score = new_score * 1000 # Convert to 0-1000 scale
reputation.reputation_level = self._determine_reputation_level(new_score)
reputation.updated_at = datetime.utcnow()
# Create event record
event = ReputationEvent(
agent_id=agent_id,
event_type='batch_update',
event_type="batch_update",
impact_score=new_score - (reputation.trust_score / 1000.0),
trust_score_before=reputation.trust_score,
trust_score_after=reputation.trust_score,
event_data=update,
occurred_at=datetime.utcnow()
occurred_at=datetime.utcnow(),
)
self.session.add(event)
results[agent_id] = True
else:
@@ -241,124 +242,117 @@ class CrossChainReputationAggregator:
trust_score=new_score * 1000,
reputation_level=self._determine_reputation_level(new_score),
created_at=datetime.utcnow(),
updated_at=datetime.utcnow()
updated_at=datetime.utcnow(),
)
self.session.add(reputation)
results[agent_id] = True
except Exception as e:
logger.error(f"Error updating reputation for agent {agent_id}: {e}")
results[agent_id] = False
self.session.commit()
# Update cross-chain aggregations
for agent_id in updates:
if results.get(agent_id):
await self._update_cross_chain_aggregation(agent_id)
return results
except Exception as e:
logger.error(f"Error in batch reputation update: {e}")
return {update['agent_id']: False for update in updates}
async def get_chain_statistics(self, chain_id: int) -> Dict[str, Any]:
return {update["agent_id"]: False for update in updates}
async def get_chain_statistics(self, chain_id: int) -> dict[str, Any]:
"""Get reputation statistics for a specific chain"""
try:
# Get all reputations for the chain
stmt = select(AgentReputation).where(
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, 'chain_id') else True
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, "chain_id") else True
)
if not hasattr(AgentReputation, 'chain_id'):
if not hasattr(AgentReputation, "chain_id"):
# For now, get all reputations
stmt = select(AgentReputation)
reputations = self.session.exec(stmt).all()
if not reputations:
return {
'chain_id': chain_id,
'total_agents': 0,
'average_reputation': 0.0,
'reputation_distribution': {},
'total_transactions': 0,
'success_rate': 0.0
"chain_id": chain_id,
"total_agents": 0,
"average_reputation": 0.0,
"reputation_distribution": {},
"total_transactions": 0,
"success_rate": 0.0,
}
# Calculate statistics
total_agents = len(reputations)
total_reputation = sum(rep.trust_score for rep in reputations)
average_reputation = total_reputation / total_agents / 1000.0 # Convert to 0-1 scale
# Reputation distribution
distribution = {}
for reputation in reputations:
level = reputation.reputation_level.value
distribution[level] = distribution.get(level, 0) + 1
# Transaction statistics
total_transactions = sum(getattr(rep, 'transaction_count', 0) for rep in reputations)
total_transactions = sum(getattr(rep, "transaction_count", 0) for rep in reputations)
successful_transactions = sum(
getattr(rep, 'transaction_count', 0) * getattr(rep, 'success_rate', 0) / 100.0
for rep in reputations
getattr(rep, "transaction_count", 0) * getattr(rep, "success_rate", 0) / 100.0 for rep in reputations
)
success_rate = successful_transactions / max(total_transactions, 1)
return {
'chain_id': chain_id,
'total_agents': total_agents,
'average_reputation': average_reputation,
'reputation_distribution': distribution,
'total_transactions': total_transactions,
'success_rate': success_rate,
'last_updated': datetime.utcnow()
"chain_id": chain_id,
"total_agents": total_agents,
"average_reputation": average_reputation,
"reputation_distribution": distribution,
"total_transactions": total_transactions,
"success_rate": success_rate,
"last_updated": datetime.utcnow(),
}
except Exception as e:
logger.error(f"Error getting chain statistics for chain {chain_id}: {e}")
return {
'chain_id': chain_id,
'error': str(e),
'total_agents': 0,
'average_reputation': 0.0
}
async def sync_cross_chain_reputations(self, agent_ids: List[str]) -> Dict[str, bool]:
return {"chain_id": chain_id, "error": str(e), "total_agents": 0, "average_reputation": 0.0}
async def sync_cross_chain_reputations(self, agent_ids: list[str]) -> dict[str, bool]:
"""Synchronize reputation data across chains for multiple agents"""
try:
results = {}
for agent_id in agent_ids:
try:
# Re-aggregate cross-chain reputation
await self._update_cross_chain_aggregation(agent_id)
results[agent_id] = True
except Exception as e:
logger.error(f"Error syncing cross-chain reputation for agent {agent_id}: {e}")
results[agent_id] = False
return results
except Exception as e:
logger.error(f"Error in cross-chain reputation sync: {e}")
return {agent_id: False for agent_id in agent_ids}
async def _get_chain_config(self, chain_id: int) -> Optional[CrossChainReputationConfig]:
return dict.fromkeys(agent_ids, False)
async def _get_chain_config(self, chain_id: int) -> CrossChainReputationConfig | None:
"""Get configuration for a specific chain"""
stmt = select(CrossChainReputationConfig).where(
CrossChainReputationConfig.chain_id == chain_id,
CrossChainReputationConfig.is_active == True
CrossChainReputationConfig.chain_id == chain_id, CrossChainReputationConfig.is_active
)
config = self.session.exec(stmt).first()
if not config:
# Create default config
config = CrossChainReputationConfig(
@@ -370,49 +364,47 @@ class CrossChainReputationAggregator:
dispute_penalty_weight=-0.3,
minimum_transactions_for_score=5,
reputation_decay_rate=0.01,
anomaly_detection_threshold=0.3
anomaly_detection_threshold=0.3,
)
self.session.add(config)
self.session.commit()
return config
async def _get_active_chain_ids(self) -> List[int]:
async def _get_active_chain_ids(self) -> list[int]:
"""Get list of active chain IDs"""
try:
stmt = select(CrossChainReputationConfig.chain_id).where(
CrossChainReputationConfig.is_active == True
)
stmt = select(CrossChainReputationConfig.chain_id).where(CrossChainReputationConfig.is_active)
configs = self.session.exec(stmt).all()
return [config.chain_id for config in configs]
except Exception as e:
logger.error(f"Error getting active chain IDs: {e}")
return [1] # Default to Ethereum mainnet
async def _update_cross_chain_aggregation(self, agent_id: str) -> None:
"""Update cross-chain aggregation for an agent"""
try:
# Get all reputations for the agent
stmt = select(AgentReputation).where(AgentReputation.agent_id == agent_id)
reputations = self.session.exec(stmt).all()
if not reputations:
return
# Extract chain scores
chain_scores = {}
for reputation in reputations:
chain_id = getattr(reputation, 'chain_id', 1)
chain_id = getattr(reputation, "chain_id", 1)
chain_scores[chain_id] = reputation.trust_score / 1000.0 # Convert to 0-1 scale
# Apply weighting
weighted_scores = await self.apply_chain_weighting(chain_scores)
await self.apply_chain_weighting(chain_scores)
# Calculate aggregation metrics
if chain_scores:
avg_score = sum(chain_scores.values()) / len(chain_scores)
@@ -424,14 +416,12 @@ class CrossChainReputationAggregator:
variance = 0.0
score_range = 0.0
consistency_score = 1.0
# Update or create aggregation
stmt = select(CrossChainReputationAggregation).where(
CrossChainReputationAggregation.agent_id == agent_id
)
stmt = select(CrossChainReputationAggregation).where(CrossChainReputationAggregation.agent_id == agent_id)
aggregation = self.session.exec(stmt).first()
if aggregation:
aggregation.aggregated_score = avg_score
aggregation.chain_scores = chain_scores
@@ -451,19 +441,19 @@ class CrossChainReputationAggregator:
consistency_score=consistency_score,
verification_status="pending",
created_at=datetime.utcnow(),
last_updated=datetime.utcnow()
last_updated=datetime.utcnow(),
)
self.session.add(aggregation)
self.session.commit()
except Exception as e:
logger.error(f"Error updating cross-chain aggregation for agent {agent_id}: {e}")
def _determine_reputation_level(self, score: float) -> str:
"""Determine reputation level based on score"""
# Map to existing reputation levels
if score >= 0.9:
return "master"

View File

@@ -3,54 +3,45 @@ Cross-Chain Reputation Engine
Core reputation calculation and aggregation engine for multi-chain agent reputation
"""
import asyncio
import math
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Any, Tuple
from uuid import uuid4
import json
import logging
from datetime import datetime, timedelta
from typing import Any
logger = logging.getLogger(__name__)
from sqlmodel import Session, select, update, delete, func
from sqlalchemy.exc import SQLAlchemyError
from sqlmodel import Session, select
from ..domain.reputation import AgentReputation, ReputationEvent, ReputationLevel
from ..domain.cross_chain_reputation import (
CrossChainReputationAggregation, CrossChainReputationEvent,
CrossChainReputationConfig, ReputationMetrics
CrossChainReputationAggregation,
CrossChainReputationConfig,
)
from ..domain.reputation import AgentReputation, ReputationEvent, ReputationLevel
class CrossChainReputationEngine:
"""Core reputation calculation and aggregation engine"""
def __init__(self, session: Session):
self.session = session
async def calculate_reputation_score(
self,
agent_id: str,
chain_id: int,
transaction_data: Optional[Dict[str, Any]] = None
self, agent_id: str, chain_id: int, transaction_data: dict[str, Any] | None = None
) -> float:
"""Calculate reputation score for an agent on a specific chain"""
try:
# Get existing reputation
stmt = select(AgentReputation).where(
AgentReputation.agent_id == agent_id,
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, 'chain_id') else True
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, "chain_id") else True,
)
# Handle case where existing reputation doesn't have chain_id
if not hasattr(AgentReputation, 'chain_id'):
if not hasattr(AgentReputation, "chain_id"):
stmt = select(AgentReputation).where(AgentReputation.agent_id == agent_id)
reputation = self.session.exec(stmt).first()
if reputation:
# Update existing reputation based on transaction data
score = await self._update_reputation_from_transaction(reputation, transaction_data)
@@ -59,122 +50,121 @@ class CrossChainReputationEngine:
config = await self._get_chain_config(chain_id)
base_score = config.base_reputation_bonus if config else 0.0
score = max(0.0, min(1.0, base_score))
# Create new reputation record
new_reputation = AgentReputation(
agent_id=agent_id,
trust_score=score * 1000, # Convert to 0-1000 scale
reputation_level=self._determine_reputation_level(score),
created_at=datetime.utcnow(),
updated_at=datetime.utcnow()
updated_at=datetime.utcnow(),
)
self.session.add(new_reputation)
self.session.commit()
return score
except Exception as e:
logger.error(f"Error calculating reputation for agent {agent_id} on chain {chain_id}: {e}")
return 0.0
async def aggregate_cross_chain_reputation(self, agent_id: str) -> Dict[int, float]:
async def aggregate_cross_chain_reputation(self, agent_id: str) -> dict[int, float]:
"""Aggregate reputation scores across all chains for an agent"""
try:
# Get all reputation records for the agent
stmt = select(AgentReputation).where(AgentReputation.agent_id == agent_id)
reputations = self.session.exec(stmt).all()
if not reputations:
return {}
# Get chain configurations
chain_configs = {}
for reputation in reputations:
chain_id = getattr(reputation, 'chain_id', 1) # Default to chain 1 if not set
chain_id = getattr(reputation, "chain_id", 1) # Default to chain 1 if not set
config = await self._get_chain_config(chain_id)
chain_configs[chain_id] = config
# Calculate weighted scores
chain_scores = {}
total_weight = 0.0
weighted_sum = 0.0
for reputation in reputations:
chain_id = getattr(reputation, 'chain_id', 1)
chain_id = getattr(reputation, "chain_id", 1)
config = chain_configs.get(chain_id)
if config and config.is_active:
# Convert trust score to 0-1 scale
score = min(1.0, reputation.trust_score / 1000.0)
weight = config.chain_weight
chain_scores[chain_id] = score
total_weight += weight
weighted_sum += score * weight
# Normalize scores
if total_weight > 0:
normalized_scores = {
chain_id: score * (total_weight / len(chain_scores))
for chain_id, score in chain_scores.items()
chain_id: score * (total_weight / len(chain_scores)) for chain_id, score in chain_scores.items()
}
else:
normalized_scores = chain_scores
# Store aggregation
await self._store_cross_chain_aggregation(agent_id, chain_scores, normalized_scores)
return chain_scores
except Exception as e:
logger.error(f"Error aggregating cross-chain reputation for agent {agent_id}: {e}")
return {}
async def update_reputation_from_event(self, event_data: Dict[str, Any]) -> bool:
async def update_reputation_from_event(self, event_data: dict[str, Any]) -> bool:
"""Update reputation from a reputation-affecting event"""
try:
agent_id = event_data['agent_id']
chain_id = event_data.get('chain_id', 1)
event_type = event_data['event_type']
impact_score = event_data['impact_score']
agent_id = event_data["agent_id"]
chain_id = event_data.get("chain_id", 1)
event_type = event_data["event_type"]
impact_score = event_data["impact_score"]
# Get existing reputation
stmt = select(AgentReputation).where(
AgentReputation.agent_id == agent_id,
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, 'chain_id') else True
AgentReputation.chain_id == chain_id if hasattr(AgentReputation, "chain_id") else True,
)
if not hasattr(AgentReputation, 'chain_id'):
if not hasattr(AgentReputation, "chain_id"):
stmt = select(AgentReputation).where(AgentReputation.agent_id == agent_id)
reputation = self.session.exec(stmt).first()
if not reputation:
# Create new reputation record
config = await self._get_chain_config(chain_id)
base_score = config.base_reputation_bonus if config else 0.0
reputation = AgentReputation(
agent_id=agent_id,
trust_score=max(0, min(1000, (base_score + impact_score) * 1000)),
reputation_level=self._determine_reputation_level(base_score + impact_score),
created_at=datetime.utcnow(),
updated_at=datetime.utcnow()
updated_at=datetime.utcnow(),
)
self.session.add(reputation)
else:
# Update existing reputation
old_score = reputation.trust_score / 1000.0
new_score = max(0.0, min(1.0, old_score + impact_score))
reputation.trust_score = new_score * 1000
reputation.reputation_level = self._determine_reputation_level(new_score)
reputation.updated_at = datetime.utcnow()
# Create reputation event record
event = ReputationEvent(
agent_id=agent_id,
@@ -183,143 +173,146 @@ class CrossChainReputationEngine:
trust_score_before=reputation.trust_score - (impact_score * 1000),
trust_score_after=reputation.trust_score,
event_data=event_data,
occurred_at=datetime.utcnow()
occurred_at=datetime.utcnow(),
)
self.session.add(event)
self.session.commit()
# Update cross-chain aggregation
await self.aggregate_cross_chain_reputation(agent_id)
logger.info(f"Updated reputation for agent {agent_id} from {event_type} event")
return True
except Exception as e:
logger.error(f"Error updating reputation from event: {e}")
return False
async def get_reputation_trend(self, agent_id: str, days: int = 30) -> List[float]:
async def get_reputation_trend(self, agent_id: str, days: int = 30) -> list[float]:
"""Get reputation trend for an agent over specified days"""
try:
# Get reputation events for the period
cutoff_date = datetime.utcnow() - timedelta(days=days)
stmt = select(ReputationEvent).where(
ReputationEvent.agent_id == agent_id,
ReputationEvent.occurred_at >= cutoff_date
).order_by(ReputationEvent.occurred_at)
stmt = (
select(ReputationEvent)
.where(ReputationEvent.agent_id == agent_id, ReputationEvent.occurred_at >= cutoff_date)
.order_by(ReputationEvent.occurred_at)
)
events = self.session.exec(stmt).all()
# Extract scores from events
scores = []
for event in events:
if event.trust_score_after is not None:
scores.append(event.trust_score_after / 1000.0) # Convert to 0-1 scale
return scores
except Exception as e:
logger.error(f"Error getting reputation trend for agent {agent_id}: {e}")
return []
async def detect_reputation_anomalies(self, agent_id: str) -> List[Dict[str, Any]]:
async def detect_reputation_anomalies(self, agent_id: str) -> list[dict[str, Any]]:
"""Detect reputation anomalies for an agent"""
try:
anomalies = []
# Get recent reputation events
stmt = select(ReputationEvent).where(
ReputationEvent.agent_id == agent_id
).order_by(ReputationEvent.occurred_at.desc()).limit(10)
stmt = (
select(ReputationEvent)
.where(ReputationEvent.agent_id == agent_id)
.order_by(ReputationEvent.occurred_at.desc())
.limit(10)
)
events = self.session.exec(stmt).all()
if len(events) < 2:
return anomalies
# Check for sudden score changes
for i in range(len(events) - 1):
current_event = events[i]
previous_event = events[i + 1]
if current_event.trust_score_after and previous_event.trust_score_after:
score_change = abs(current_event.trust_score_after - previous_event.trust_score_after) / 1000.0
if score_change > 0.3: # 30% change threshold
anomalies.append({
'agent_id': agent_id,
'chain_id': getattr(current_event, 'chain_id', 1),
'anomaly_type': 'sudden_score_change',
'detected_at': current_event.occurred_at,
'description': f"Sudden reputation change of {score_change:.2f}",
'severity': 'high' if score_change > 0.5 else 'medium',
'previous_score': previous_event.trust_score_after / 1000.0,
'current_score': current_event.trust_score_after / 1000.0,
'score_change': score_change,
'confidence': min(1.0, score_change / 0.3)
})
anomalies.append(
{
"agent_id": agent_id,
"chain_id": getattr(current_event, "chain_id", 1),
"anomaly_type": "sudden_score_change",
"detected_at": current_event.occurred_at,
"description": f"Sudden reputation change of {score_change:.2f}",
"severity": "high" if score_change > 0.5 else "medium",
"previous_score": previous_event.trust_score_after / 1000.0,
"current_score": current_event.trust_score_after / 1000.0,
"score_change": score_change,
"confidence": min(1.0, score_change / 0.3),
}
)
return anomalies
except Exception as e:
logger.error(f"Error detecting reputation anomalies for agent {agent_id}: {e}")
return []
async def _update_reputation_from_transaction(
self,
reputation: AgentReputation,
transaction_data: Optional[Dict[str, Any]]
self, reputation: AgentReputation, transaction_data: dict[str, Any] | None
) -> float:
"""Update reputation based on transaction data"""
if not transaction_data:
return reputation.trust_score / 1000.0
# Extract transaction metrics
success = transaction_data.get('success', True)
gas_efficiency = transaction_data.get('gas_efficiency', 0.5)
response_time = transaction_data.get('response_time', 1.0)
success = transaction_data.get("success", True)
gas_efficiency = transaction_data.get("gas_efficiency", 0.5)
response_time = transaction_data.get("response_time", 1.0)
# Calculate impact based on transaction outcome
config = await self._get_chain_config(getattr(reputation, 'chain_id', 1))
config = await self._get_chain_config(getattr(reputation, "chain_id", 1))
if success:
impact = config.transaction_success_weight if config else 0.1
impact *= gas_efficiency # Bonus for gas efficiency
impact *= (2.0 - min(response_time, 2.0)) # Bonus for fast response
impact *= 2.0 - min(response_time, 2.0) # Bonus for fast response
else:
impact = config.transaction_failure_weight if config else -0.2
# Update reputation
old_score = reputation.trust_score / 1000.0
new_score = max(0.0, min(1.0, old_score + impact))
reputation.trust_score = new_score * 1000
reputation.reputation_level = self._determine_reputation_level(new_score)
reputation.updated_at = datetime.utcnow()
# Update transaction metrics if available
if 'transaction_count' in transaction_data:
reputation.transaction_count = transaction_data['transaction_count']
if "transaction_count" in transaction_data:
reputation.transaction_count = transaction_data["transaction_count"]
self.session.commit()
return new_score
async def _get_chain_config(self, chain_id: int) -> Optional[CrossChainReputationConfig]:
async def _get_chain_config(self, chain_id: int) -> CrossChainReputationConfig | None:
"""Get configuration for a specific chain"""
stmt = select(CrossChainReputationConfig).where(
CrossChainReputationConfig.chain_id == chain_id,
CrossChainReputationConfig.is_active == True
CrossChainReputationConfig.chain_id == chain_id, CrossChainReputationConfig.is_active
)
config = self.session.exec(stmt).first()
if not config:
# Create default config
config = CrossChainReputationConfig(
@@ -331,22 +324,19 @@ class CrossChainReputationEngine:
dispute_penalty_weight=-0.3,
minimum_transactions_for_score=5,
reputation_decay_rate=0.01,
anomaly_detection_threshold=0.3
anomaly_detection_threshold=0.3,
)
self.session.add(config)
self.session.commit()
return config
async def _store_cross_chain_aggregation(
self,
agent_id: str,
chain_scores: Dict[int, float],
normalized_scores: Dict[int, float]
self, agent_id: str, chain_scores: dict[int, float], normalized_scores: dict[int, float]
) -> None:
"""Store cross-chain reputation aggregation"""
try:
# Calculate aggregation metrics
if chain_scores:
@@ -359,14 +349,12 @@ class CrossChainReputationEngine:
variance = 0.0
score_range = 0.0
consistency_score = 1.0
# Check if aggregation already exists
stmt = select(CrossChainReputationAggregation).where(
CrossChainReputationAggregation.agent_id == agent_id
)
stmt = select(CrossChainReputationAggregation).where(CrossChainReputationAggregation.agent_id == agent_id)
aggregation = self.session.exec(stmt).first()
if aggregation:
# Update existing aggregation
aggregation.aggregated_score = avg_score
@@ -388,19 +376,19 @@ class CrossChainReputationEngine:
consistency_score=consistency_score,
verification_status="pending",
created_at=datetime.utcnow(),
last_updated=datetime.utcnow()
last_updated=datetime.utcnow(),
)
self.session.add(aggregation)
self.session.commit()
except Exception as e:
logger.error(f"Error storing cross-chain aggregation for agent {agent_id}: {e}")
def _determine_reputation_level(self, score: float) -> ReputationLevel:
"""Determine reputation level based on score"""
if score >= 0.9:
return ReputationLevel.MASTER
elif score >= 0.8:
@@ -413,65 +401,58 @@ class CrossChainReputationEngine:
return ReputationLevel.BEGINNER
else:
return ReputationLevel.BEGINNER # Map to existing levels
async def get_agent_reputation_summary(self, agent_id: str) -> Dict[str, Any]:
async def get_agent_reputation_summary(self, agent_id: str) -> dict[str, Any]:
"""Get comprehensive reputation summary for an agent"""
try:
# Get basic reputation
stmt = select(AgentReputation).where(AgentReputation.agent_id == agent_id)
reputation = self.session.exec(stmt).first()
if not reputation:
return {
'agent_id': agent_id,
'trust_score': 0.0,
'reputation_level': ReputationLevel.BEGINNER,
'total_transactions': 0,
'success_rate': 0.0,
'cross_chain': {
'aggregated_score': 0.0,
'chain_count': 0,
'active_chains': [],
'consistency_score': 1.0
}
"agent_id": agent_id,
"trust_score": 0.0,
"reputation_level": ReputationLevel.BEGINNER,
"total_transactions": 0,
"success_rate": 0.0,
"cross_chain": {"aggregated_score": 0.0, "chain_count": 0, "active_chains": [], "consistency_score": 1.0},
}
# Get cross-chain aggregation
stmt = select(CrossChainReputationAggregation).where(
CrossChainReputationAggregation.agent_id == agent_id
)
stmt = select(CrossChainReputationAggregation).where(CrossChainReputationAggregation.agent_id == agent_id)
aggregation = self.session.exec(stmt).first()
# Get reputation trend
trend = await self.get_reputation_trend(agent_id, 30)
# Get anomalies
anomalies = await self.detect_reputation_anomalies(agent_id)
return {
'agent_id': agent_id,
'trust_score': reputation.trust_score,
'reputation_level': reputation.reputation_level,
'performance_rating': getattr(reputation, 'performance_rating', 3.0),
'reliability_score': getattr(reputation, 'reliability_score', 50.0),
'total_transactions': getattr(reputation, 'transaction_count', 0),
'success_rate': getattr(reputation, 'success_rate', 0.0),
'dispute_count': getattr(reputation, 'dispute_count', 0),
'last_activity': getattr(reputation, 'last_activity', datetime.utcnow()),
'cross_chain': {
'aggregated_score': aggregation.aggregated_score if aggregation else 0.0,
'chain_count': aggregation.chain_count if aggregation else 0,
'active_chains': aggregation.active_chains if aggregation else [],
'consistency_score': aggregation.consistency_score if aggregation else 1.0,
'chain_scores': aggregation.chain_scores if aggregation else {}
"agent_id": agent_id,
"trust_score": reputation.trust_score,
"reputation_level": reputation.reputation_level,
"performance_rating": getattr(reputation, "performance_rating", 3.0),
"reliability_score": getattr(reputation, "reliability_score", 50.0),
"total_transactions": getattr(reputation, "transaction_count", 0),
"success_rate": getattr(reputation, "success_rate", 0.0),
"dispute_count": getattr(reputation, "dispute_count", 0),
"last_activity": getattr(reputation, "last_activity", datetime.utcnow()),
"cross_chain": {
"aggregated_score": aggregation.aggregated_score if aggregation else 0.0,
"chain_count": aggregation.chain_count if aggregation else 0,
"active_chains": aggregation.active_chains if aggregation else [],
"consistency_score": aggregation.consistency_score if aggregation else 1.0,
"chain_scores": aggregation.chain_scores if aggregation else {},
},
'trend': trend,
'anomalies': anomalies,
'created_at': reputation.created_at,
'updated_at': reputation.updated_at
"trend": trend,
"anomalies": anomalies,
"created_at": reputation.created_at,
"updated_at": reputation.updated_at,
}
except Exception as e:
logger.error(f"Error getting reputation summary for agent {agent_id}: {e}")
return {'agent_id': agent_id, 'error': str(e)}
return {"agent_id": agent_id, "error": str(e)}