fix: resolve CI failures across all workflows
All checks were successful
API Endpoint Tests / test-api-endpoints (push) Successful in 39s
Integration Tests / test-service-integration (push) Successful in 44s
Package Tests / test-python-packages (map[name:aitbc-core path:packages/py/aitbc-core]) (push) Successful in 16s
Package Tests / test-python-packages (map[name:aitbc-agent-sdk path:packages/py/aitbc-agent-sdk]) (push) Successful in 30s
Package Tests / test-python-packages (map[name:aitbc-crypto path:packages/py/aitbc-crypto]) (push) Successful in 20s
Package Tests / test-python-packages (map[name:aitbc-sdk path:packages/py/aitbc-sdk]) (push) Successful in 20s
Package Tests / test-javascript-packages (map[name:aitbc-sdk-js path:packages/js/aitbc-sdk]) (push) Successful in 17s
Package Tests / test-javascript-packages (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Successful in 1m17s
Python Tests / test-python (push) Successful in 1m7s
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Successful in 30s
Security Scanning / security-scan (push) Successful in 1m5s
Smart Contract Tests / test-solidity (map[name:zk-circuits path:apps/zk-circuits]) (push) Successful in 49s
Smart Contract Tests / lint-solidity (push) Successful in 54s
All checks were successful
API Endpoint Tests / test-api-endpoints (push) Successful in 39s
Integration Tests / test-service-integration (push) Successful in 44s
Package Tests / test-python-packages (map[name:aitbc-core path:packages/py/aitbc-core]) (push) Successful in 16s
Package Tests / test-python-packages (map[name:aitbc-agent-sdk path:packages/py/aitbc-agent-sdk]) (push) Successful in 30s
Package Tests / test-python-packages (map[name:aitbc-crypto path:packages/py/aitbc-crypto]) (push) Successful in 20s
Package Tests / test-python-packages (map[name:aitbc-sdk path:packages/py/aitbc-sdk]) (push) Successful in 20s
Package Tests / test-javascript-packages (map[name:aitbc-sdk-js path:packages/js/aitbc-sdk]) (push) Successful in 17s
Package Tests / test-javascript-packages (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Successful in 1m17s
Python Tests / test-python (push) Successful in 1m7s
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Successful in 30s
Security Scanning / security-scan (push) Successful in 1m5s
Smart Contract Tests / test-solidity (map[name:zk-circuits path:apps/zk-circuits]) (push) Successful in 49s
Smart Contract Tests / lint-solidity (push) Successful in 54s
aitbc-agent-sdk (package-tests.yml): - Add AITBCAgent convenience class matching test expectations - Fix test_agent_sdk.py: was importing nonexistent AITBCAgent, now tests the real API (Agent.create, AgentCapabilities, to_dict) plus AITBCAgent - Fix 3 remaining mypy errors: supported_models Optional coercion (line 64), missing return types on _submit_to_marketplace/_update_marketplace_offer - Run black on all 5 src files — zero mypy errors, zero black warnings - All 6 tests pass python-tests.yml: - Add pynacl to pip install (aitbc-crypto and aitbc-sdk import nacl) - Add pynacl>=1.5.0 to root requirements.txt Service readiness (api-endpoint-tests.yml, integration-tests.yml): - Replace curl -sf with curl http_code check — -sf fails on 404 responses but port 8006 (blockchain RPC) returns 404 on / while being healthy - Blockchain RPC uses REST /rpc/* endpoints, not JSON-RPC POST to / Fix test_api_endpoints.py to test /health, /rpc/head, /rpc/info, /rpc/supply - Remove dead test_rpc() function, add blockchain RPC to perf tests - All 4 services now pass: coordinator, exchange, wallet, blockchain_rpc - Integration-tests: check is-active before systemctl start to avoid spurious warnings for already-running services Hardhat compile (smart-contract-tests.yml, package-tests.yml): - Relax engines field from >=24.14.0 to >=18.0.0 (CI has v24.13.0) - Remove 2>/dev/null from hardhat compile/test so errors are visible - Remove 2>/dev/null from npm run build/test in package-tests JS section
This commit is contained in:
@@ -16,123 +16,123 @@ from cryptography.hazmat.primitives.asymmetric import padding
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentCapabilities:
|
||||
"""Agent capability specification"""
|
||||
|
||||
compute_type: str # "inference", "training", "processing"
|
||||
gpu_memory: Optional[int] = None
|
||||
supported_models: Optional[List[str]] = None
|
||||
performance_score: float = 0.0
|
||||
max_concurrent_jobs: int = 1
|
||||
specialization: Optional[str] = None
|
||||
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.supported_models is None:
|
||||
self.supported_models = []
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentIdentity:
|
||||
"""Agent identity and cryptographic keys"""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
address: str
|
||||
public_key: str
|
||||
private_key: str
|
||||
|
||||
|
||||
def sign_message(self, message: Dict[str, Any]) -> str:
|
||||
"""Sign a message with agent's private key"""
|
||||
message_str = json.dumps(message, sort_keys=True)
|
||||
private_key = serialization.load_pem_private_key(
|
||||
self.private_key.encode(),
|
||||
password=None
|
||||
self.private_key.encode(), password=None
|
||||
)
|
||||
|
||||
|
||||
if not isinstance(private_key, rsa.RSAPrivateKey):
|
||||
raise TypeError("Only RSA private keys are supported")
|
||||
|
||||
|
||||
signature = private_key.sign(
|
||||
message_str.encode(),
|
||||
padding.PSS(
|
||||
mgf=padding.MGF1(hashes.SHA256()),
|
||||
salt_length=padding.PSS.MAX_LENGTH
|
||||
mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH
|
||||
),
|
||||
hashes.SHA256()
|
||||
hashes.SHA256(),
|
||||
)
|
||||
|
||||
|
||||
return signature.hex()
|
||||
|
||||
|
||||
def verify_signature(self, message: Dict[str, Any], signature: str) -> bool:
|
||||
"""Verify a message signature"""
|
||||
message_str = json.dumps(message, sort_keys=True)
|
||||
public_key = serialization.load_pem_public_key(
|
||||
self.public_key.encode()
|
||||
)
|
||||
|
||||
public_key = serialization.load_pem_public_key(self.public_key.encode())
|
||||
|
||||
if not isinstance(public_key, rsa.RSAPublicKey):
|
||||
raise TypeError("Only RSA public keys are supported")
|
||||
|
||||
|
||||
try:
|
||||
public_key.verify(
|
||||
bytes.fromhex(signature),
|
||||
message_str.encode(),
|
||||
padding.PSS(
|
||||
mgf=padding.MGF1(hashes.SHA256()),
|
||||
salt_length=padding.PSS.MAX_LENGTH
|
||||
salt_length=padding.PSS.MAX_LENGTH,
|
||||
),
|
||||
hashes.SHA256()
|
||||
hashes.SHA256(),
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class Agent:
|
||||
"""Core AITBC Agent class"""
|
||||
|
||||
|
||||
def __init__(self, identity: AgentIdentity, capabilities: AgentCapabilities):
|
||||
self.identity = identity
|
||||
self.capabilities = capabilities
|
||||
self.registered = False
|
||||
self.reputation_score = 0.0
|
||||
self.earnings = 0.0
|
||||
|
||||
|
||||
@classmethod
|
||||
def create(cls, name: str, agent_type: str, capabilities: Dict[str, Any]) -> 'Agent':
|
||||
def create(
|
||||
cls, name: str, agent_type: str, capabilities: Dict[str, Any]
|
||||
) -> "Agent":
|
||||
"""Create a new agent with generated identity"""
|
||||
# Generate cryptographic keys
|
||||
private_key = rsa.generate_private_key(
|
||||
public_exponent=65537,
|
||||
key_size=2048
|
||||
)
|
||||
|
||||
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
|
||||
public_key = private_key.public_key()
|
||||
private_pem = private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
encryption_algorithm=serialization.NoEncryption(),
|
||||
)
|
||||
|
||||
|
||||
public_pem = public_key.public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
)
|
||||
|
||||
|
||||
# Generate agent identity
|
||||
agent_id = f"agent_{uuid.uuid4().hex[:8]}"
|
||||
address = f"0x{uuid.uuid4().hex[:40]}"
|
||||
|
||||
|
||||
identity = AgentIdentity(
|
||||
id=agent_id,
|
||||
name=name,
|
||||
address=address,
|
||||
public_key=public_pem.decode(),
|
||||
private_key=private_pem.decode()
|
||||
private_key=private_pem.decode(),
|
||||
)
|
||||
|
||||
|
||||
# Create capabilities object
|
||||
agent_capabilities = AgentCapabilities(**capabilities)
|
||||
|
||||
|
||||
return cls(identity, agent_capabilities)
|
||||
|
||||
|
||||
async def register(self) -> bool:
|
||||
"""Register the agent on the AITBC network"""
|
||||
try:
|
||||
@@ -147,27 +147,27 @@ class Agent:
|
||||
"supported_models": self.capabilities.supported_models,
|
||||
"performance_score": self.capabilities.performance_score,
|
||||
"max_concurrent_jobs": self.capabilities.max_concurrent_jobs,
|
||||
"specialization": self.capabilities.specialization
|
||||
"specialization": self.capabilities.specialization,
|
||||
},
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
# Sign registration data
|
||||
signature = self.identity.sign_message(registration_data)
|
||||
registration_data["signature"] = signature
|
||||
|
||||
|
||||
# TODO: Submit to AITBC network registration endpoint
|
||||
# For now, simulate successful registration
|
||||
await asyncio.sleep(1) # Simulate network call
|
||||
|
||||
|
||||
self.registered = True
|
||||
logger.info(f"Agent {self.identity.id} registered successfully")
|
||||
return True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Registration failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
async def get_reputation(self) -> Dict[str, float]:
|
||||
"""Get agent reputation metrics"""
|
||||
# TODO: Fetch from reputation system
|
||||
@@ -175,14 +175,14 @@ class Agent:
|
||||
"overall_score": self.reputation_score,
|
||||
"job_success_rate": 0.95,
|
||||
"avg_response_time": 30.5,
|
||||
"client_satisfaction": 4.7
|
||||
"client_satisfaction": 4.7,
|
||||
}
|
||||
|
||||
|
||||
async def update_reputation(self, new_score: float) -> None:
|
||||
"""Update agent reputation score"""
|
||||
self.reputation_score = new_score
|
||||
logger.info(f"Reputation updated to {new_score}")
|
||||
|
||||
|
||||
async def get_earnings(self, period: str = "30d") -> Dict[str, Any]:
|
||||
"""Get agent earnings information"""
|
||||
# TODO: Fetch from blockchain/payment system
|
||||
@@ -190,38 +190,42 @@ class Agent:
|
||||
"total": self.earnings,
|
||||
"daily_average": self.earnings / 30,
|
||||
"period": period,
|
||||
"currency": "AITBC"
|
||||
"currency": "AITBC",
|
||||
}
|
||||
|
||||
async def send_message(self, recipient_id: str, message_type: str, payload: Dict[str, Any]) -> bool:
|
||||
|
||||
async def send_message(
|
||||
self, recipient_id: str, message_type: str, payload: Dict[str, Any]
|
||||
) -> bool:
|
||||
"""Send a message to another agent"""
|
||||
message = {
|
||||
"from": self.identity.id,
|
||||
"to": recipient_id,
|
||||
"type": message_type,
|
||||
"payload": payload,
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
|
||||
|
||||
# Sign message
|
||||
signature = self.identity.sign_message(message)
|
||||
message["signature"] = signature
|
||||
|
||||
|
||||
# TODO: Send through AITBC agent messaging protocol
|
||||
logger.info(f"Message sent to {recipient_id}: {message_type}")
|
||||
return True
|
||||
|
||||
|
||||
async def receive_message(self, message: Dict[str, Any]) -> bool:
|
||||
"""Process a received message from another agent"""
|
||||
# Verify signature
|
||||
if "signature" not in message:
|
||||
return False
|
||||
|
||||
|
||||
# TODO: Verify sender's signature
|
||||
# For now, just process the message
|
||||
logger.info(f"Received message from {message.get('from')}: {message.get('type')}")
|
||||
logger.info(
|
||||
f"Received message from {message.get('from')}: {message.get('type')}"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Convert agent to dictionary representation"""
|
||||
return {
|
||||
@@ -234,9 +238,48 @@ class Agent:
|
||||
"supported_models": self.capabilities.supported_models,
|
||||
"performance_score": self.capabilities.performance_score,
|
||||
"max_concurrent_jobs": self.capabilities.max_concurrent_jobs,
|
||||
"specialization": self.capabilities.specialization
|
||||
"specialization": self.capabilities.specialization,
|
||||
},
|
||||
"reputation_score": self.reputation_score,
|
||||
"registered": self.registered,
|
||||
"earnings": self.earnings
|
||||
"earnings": self.earnings,
|
||||
}
|
||||
|
||||
|
||||
class AITBCAgent:
|
||||
"""High-level convenience wrapper for creating AITBC agents.
|
||||
|
||||
Provides a simple keyword-argument constructor suitable for quick
|
||||
prototyping and testing without manually building AgentIdentity /
|
||||
AgentCapabilities objects.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_id: str = "",
|
||||
compute_type: str = "general",
|
||||
capabilities: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
self.agent_id = agent_id
|
||||
self.compute_type = compute_type
|
||||
self.capabilities: List[str] = capabilities or []
|
||||
self.status = "initialized"
|
||||
self._extra = kwargs
|
||||
|
||||
# Build a backing Agent for crypto / network operations
|
||||
self._agent = Agent.create(
|
||||
name=agent_id,
|
||||
agent_type=compute_type,
|
||||
capabilities={"compute_type": compute_type},
|
||||
)
|
||||
|
||||
# Delegate common Agent methods
|
||||
async def register(self) -> bool:
|
||||
return await self._agent.register()
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
d = self._agent.to_dict()
|
||||
d["agent_id"] = self.agent_id
|
||||
d["status"] = self.status
|
||||
return d
|
||||
|
||||
Reference in New Issue
Block a user