Update Python version requirements and fix compatibility issues

- Bump minimum Python version from 3.11 to 3.13 across all apps
- Add Python 3.11-3.13 test matrix to CLI workflow
- Document Python 3.11+ requirement in .env.example
- Fix Starlette Broadcast removal with in-process fallback implementation
- Add _InProcessBroadcast class for tests when Starlette Broadcast is unavailable
- Refactor API key validators to read live settings instead of cached values
- Update database models with explicit
This commit is contained in:
oib
2026-02-24 18:41:08 +01:00
parent 24b3a37733
commit 825f157749
270 changed files with 66674 additions and 2027 deletions

View File

@@ -199,7 +199,7 @@ export class AitbcClient {
await this.request<void>("POST", "/v1/users/logout", options);
}
private async request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {
async request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {
const response = await this.rawRequest(method, path, options);
const text = await response.text();
if (!response.ok) {
@@ -208,7 +208,7 @@ export class AitbcClient {
return text ? (JSON.parse(text) as T) : ({} as T);
}
private async rawRequest(method: string, path: string, options: RequestOptions = {}): Promise<Response> {
async rawRequest(method: string, path: string, options: RequestOptions = {}): Promise<Response> {
const url = this.buildUrl(path, options.query);
const headers = this.buildHeaders(options.headers);

View File

@@ -0,0 +1,77 @@
import { describe, expect, it } from "vitest";
import { generateKeyPairSync, sign } from "crypto";
import { ReceiptService } from "./receipts";
import type { ReceiptSummary } from "./types";
class ThrowingClient {
async request() {
throw new Error("offline");
}
}
describe("ReceiptService signature verification", () => {
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
const publicKeyPem = publicKey.export({ type: "spki", format: "pem" }).toString();
const baseReceipt: ReceiptSummary = {
receiptId: "r1",
jobId: "job-123",
miner: "miner-1",
coordinator: "coord-1",
issuedAt: new Date().toISOString(),
status: "completed",
payload: {
job_id: "job-123",
provider: "miner-1",
client: "client-1",
},
};
const signPayload = (payload: Record<string, unknown>): string => {
const message = Buffer.from(JSON.stringify(payload));
return sign(null, message, privateKey).toString("base64");
};
it("validates with provided PEM keys", async () => {
const sig = signPayload(baseReceipt.payload!);
const receipt: ReceiptSummary = {
...baseReceipt,
payload: {
...baseReceipt.payload,
minerSignature: sig,
coordinatorSignature: sig,
},
};
const svc = new ReceiptService({
client: new ThrowingClient() as any,
minerPublicKeyPem: publicKeyPem,
coordinatorPublicKeyPem: publicKeyPem,
signatureAlgorithm: "ed25519",
});
const result = await svc.validateReceipt(receipt);
expect(result.valid).toBe(true);
});
it("fails with bad signature", async () => {
const receipt: ReceiptSummary = {
...baseReceipt,
payload: {
...baseReceipt.payload,
minerSignature: "bad",
coordinatorSignature: "bad",
},
};
const svc = new ReceiptService({
client: new ThrowingClient() as any,
minerPublicKeyPem: publicKeyPem,
coordinatorPublicKeyPem: publicKeyPem,
signatureAlgorithm: "ed25519",
});
const result = await svc.validateReceipt(receipt);
expect(result.valid).toBe(false);
});
});

View File

@@ -0,0 +1,209 @@
import { verify as verifySignature, createPublicKey } from "crypto";
import type { ReceiptListResponse, ReceiptSummary, RequestOptions } from "./types";
import { AitbcClient } from "./client";
export interface PaginatedReceipts {
items: ReceiptSummary[];
nextCursor?: string | null;
}
export interface ReceiptValidationResult {
valid: boolean;
reason?: string;
}
export interface ReceiptValidationOptions extends RequestOptions {
minerVerifier?: (receipt: ReceiptSummary) => Promise<boolean> | boolean;
coordinatorVerifier?: (receipt: ReceiptSummary) => Promise<boolean> | boolean;
minerPublicKeyPem?: string;
coordinatorPublicKeyPem?: string;
signatureAlgorithm?: "ed25519" | "secp256k1" | "rsa" | string;
}
export interface ReceiptServiceOptions {
client: AitbcClient;
maxRetries?: number;
retryDelayMs?: number;
minerPublicKeyPem?: string;
coordinatorPublicKeyPem?: string;
signatureAlgorithm?: "ed25519" | "secp256k1" | "rsa" | string;
}
export class ReceiptService {
private client: AitbcClient;
private maxRetries: number;
private retryDelayMs: number;
private minerPublicKeyPem?: string;
private coordinatorPublicKeyPem?: string;
private signatureAlgorithm?: string;
constructor(opts: ReceiptServiceOptions) {
this.client = opts.client;
this.maxRetries = opts.maxRetries ?? 3;
this.retryDelayMs = opts.retryDelayMs ?? 250;
this.minerPublicKeyPem = opts.minerPublicKeyPem;
this.coordinatorPublicKeyPem = opts.coordinatorPublicKeyPem;
this.signatureAlgorithm = opts.signatureAlgorithm ?? "ed25519";
}
async getJobReceipts(
jobId: string,
cursor?: string,
limit: number = 50,
options?: RequestOptions,
): Promise<PaginatedReceipts> {
let attempt = 0;
let lastError: unknown;
while (attempt <= this.maxRetries) {
try {
const data = await this.client.request<ReceiptListResponse & { next_cursor?: string }>(
"GET",
`/v1/jobs/${jobId}/receipts`,
{
...options,
query: {
cursor,
limit,
},
}
);
return {
items: (data.items ?? []).filter((r) => !r.jobId || r.jobId === jobId),
nextCursor: data.next_cursor ?? (data as any).nextCursor ?? null,
};
} catch (err) {
lastError = err;
attempt += 1;
if (attempt > this.maxRetries) break;
await this.delay(this.retryDelayMs * attempt);
}
}
throw lastError ?? new Error("Failed to fetch receipts");
}
async validateReceipt(receipt: ReceiptSummary, options?: ReceiptValidationOptions): Promise<ReceiptValidationResult> {
// Placeholder for full cryptographic verification: delegate to coordinator API
const {
minerVerifier,
coordinatorVerifier,
minerPublicKeyPem,
coordinatorPublicKeyPem,
signatureAlgorithm,
...requestOptions
} = options ?? {};
try {
const data = await this.client.request<{ valid: boolean; reason?: string }>(
"POST",
"/v1/receipts/verify",
{
...requestOptions,
body: JSON.stringify(this.buildVerificationPayload(receipt)),
}
);
return { valid: !!data.valid, reason: data.reason };
} catch (err) {
// Fallback to local checks if API unavailable
const local = await this.validateLocally(
receipt,
minerVerifier,
coordinatorVerifier,
minerPublicKeyPem ?? this.minerPublicKeyPem,
coordinatorPublicKeyPem ?? this.coordinatorPublicKeyPem,
signatureAlgorithm ?? this.signatureAlgorithm ?? "ed25519"
);
return local.valid ? local : { valid: false, reason: (err as Error).message };
}
}
buildVerificationPayload(receipt: ReceiptSummary) {
return {
receipt_id: receipt.receiptId,
job_id: receipt.jobId,
miner: receipt.miner,
coordinator: receipt.coordinator,
issued_at: receipt.issuedAt,
status: receipt.status,
payload: receipt.payload,
};
}
async validateLocally(
receipt: ReceiptSummary,
minerVerifier?: (receipt: ReceiptSummary) => Promise<boolean> | boolean,
coordinatorVerifier?: (receipt: ReceiptSummary) => Promise<boolean> | boolean,
minerPublicKeyPem?: string,
coordinatorPublicKeyPem?: string,
signatureAlgorithm: string = "ed25519",
): Promise<ReceiptValidationResult> {
const payload = receipt.payload ?? {};
const sig = payload.signature ?? {};
const minerSig = payload.minerSignature ?? sig.sig;
const coordinatorSig = payload.coordinatorSignature ?? sig.sig;
if (!minerSig) {
return { valid: false, reason: "missing miner signature" };
}
if (!coordinatorSig) {
return { valid: false, reason: "missing coordinator signature" };
}
if (!payload.job_id && receipt.jobId) {
return { valid: false, reason: "missing job_id in payload" };
}
const payloadForSig = this.sanitizePayload(payload);
if (minerVerifier) {
const ok = await minerVerifier(receipt);
if (!ok) return { valid: false, reason: "miner signature invalid" };
} else if (minerPublicKeyPem) {
const ok = this.verifyWithCrypto(minerSig, minerPublicKeyPem, payloadForSig, signatureAlgorithm);
if (!ok) return { valid: false, reason: "miner signature invalid" };
}
if (coordinatorVerifier) {
const ok = await coordinatorVerifier(receipt);
if (!ok) return { valid: false, reason: "coordinator signature invalid" };
} else if (coordinatorPublicKeyPem) {
const ok = this.verifyWithCrypto(coordinatorSig, coordinatorPublicKeyPem, payloadForSig, signatureAlgorithm);
if (!ok) return { valid: false, reason: "coordinator signature invalid" };
}
return { valid: true };
}
private sanitizePayload(payload: Record<string, unknown>): Record<string, unknown> {
const { signature, minerSignature, coordinatorSignature, ...rest } = payload ?? {};
return rest;
}
private verifyWithCrypto(
signatureBase64: string,
publicKeyPem: string,
payload: Record<string, unknown>,
alg: string,
): boolean {
try {
const key = createPublicKey(publicKeyPem);
const message = Buffer.from(JSON.stringify(payload ?? {}));
const sig = Buffer.from(signatureBase64, "base64");
if (alg.toLowerCase() === "ed25519") {
return verifySignature(null, message, key, sig);
}
if (alg.toLowerCase() === "secp256k1") {
return verifySignature("sha256", message, { key, dsaEncoding: "ieee-p1363" }, sig);
}
if (alg.toLowerCase().startsWith("rsa")) {
return verifySignature("sha256", message, key, sig);
}
// Unknown alg: fail closed
return false;
} catch (e) {
return false;
}
}
private async delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}

View File

@@ -0,0 +1,18 @@
"""
AITBC Agent SDK - Python SDK for AI agents to participate in the AITBC network
"""
from .agent import Agent
from .compute_provider import ComputeProvider
from .compute_consumer import ComputeConsumer
from .platform_builder import PlatformBuilder
from .swarm_coordinator import SwarmCoordinator
__version__ = "1.0.0"
__all__ = [
"Agent",
"ComputeProvider",
"ComputeConsumer",
"PlatformBuilder",
"SwarmCoordinator"
]

View File

@@ -0,0 +1,233 @@
"""
Core Agent class for AITBC network participation
"""
import asyncio
import json
import uuid
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
@dataclass
class AgentCapabilities:
"""Agent capability specification"""
compute_type: str # "inference", "training", "processing"
gpu_memory: Optional[int] = None
supported_models: List[str] = None
performance_score: float = 0.0
max_concurrent_jobs: int = 1
specialization: Optional[str] = None
def __post_init__(self):
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
)
signature = private_key.sign(
message_str.encode(),
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
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()
)
try:
public_key.verify(
bytes.fromhex(signature),
message_str.encode(),
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
return True
except:
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':
"""Create a new agent with generated identity"""
# Generate cryptographic keys
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()
)
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
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()
)
# 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:
registration_data = {
"agent_id": self.identity.id,
"name": self.identity.name,
"address": self.identity.address,
"public_key": self.identity.public_key,
"capabilities": {
"compute_type": self.capabilities.compute_type,
"gpu_memory": self.capabilities.gpu_memory,
"supported_models": self.capabilities.supported_models,
"performance_score": self.capabilities.performance_score,
"max_concurrent_jobs": self.capabilities.max_concurrent_jobs,
"specialization": self.capabilities.specialization
},
"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
print(f"Agent {self.identity.id} registered successfully")
return True
except Exception as e:
print(f"Registration failed: {e}")
return False
async def get_reputation(self) -> Dict[str, float]:
"""Get agent reputation metrics"""
# TODO: Fetch from reputation system
return {
"overall_score": self.reputation_score,
"job_success_rate": 0.95,
"avg_response_time": 30.5,
"client_satisfaction": 4.7
}
async def update_reputation(self, new_score: float) -> None:
"""Update agent reputation score"""
self.reputation_score = new_score
print(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
return {
"total": self.earnings,
"daily_average": self.earnings / 30,
"period": period,
"currency": "AITBC"
}
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()
}
# Sign message
signature = self.identity.sign_message(message)
message["signature"] = signature
# TODO: Send through AITBC agent messaging protocol
print(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
print(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 {
"id": self.identity.id,
"name": self.identity.name,
"address": self.identity.address,
"capabilities": {
"compute_type": self.capabilities.compute_type,
"gpu_memory": self.capabilities.gpu_memory,
"supported_models": self.capabilities.supported_models,
"performance_score": self.capabilities.performance_score,
"max_concurrent_jobs": self.capabilities.max_concurrent_jobs,
"specialization": self.capabilities.specialization
},
"reputation_score": self.reputation_score,
"registered": self.registered,
"earnings": self.earnings
}

View File

@@ -0,0 +1,251 @@
"""
Compute Provider Agent - for agents that provide computational resources
"""
import asyncio
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
from dataclasses import dataclass
from .agent import Agent, AgentCapabilities
@dataclass
class ResourceOffer:
"""Resource offering specification"""
provider_id: str
compute_type: str
gpu_memory: int
supported_models: List[str]
price_per_hour: float
availability_schedule: Dict[str, Any]
max_concurrent_jobs: int
quality_guarantee: float = 0.95
@dataclass
class JobExecution:
"""Job execution tracking"""
job_id: str
consumer_id: str
start_time: datetime
expected_duration: timedelta
actual_duration: Optional[timedelta] = None
status: str = "running" # running, completed, failed
quality_score: Optional[float] = None
class ComputeProvider(Agent):
"""Agent that provides computational resources"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.current_offers: List[ResourceOffer] = []
self.active_jobs: List[JobExecution] = []
self.earnings = 0.0
self.utilization_rate = 0.0
@classmethod
def register(cls, name: str, capabilities: Dict[str, Any], pricing_model: Dict[str, Any]) -> 'ComputeProvider':
"""Register as a compute provider"""
agent = super().create(name, "compute_provider", capabilities)
provider = cls(agent.identity, agent.capabilities)
provider.pricing_model = pricing_model
return provider
async def offer_resources(self, price_per_hour: float, availability_schedule: Dict[str, Any], max_concurrent_jobs: int = 3) -> bool:
"""Offer computational resources on the marketplace"""
try:
offer = ResourceOffer(
provider_id=self.identity.id,
compute_type=self.capabilities.compute_type,
gpu_memory=self.capabilities.gpu_memory or 0,
supported_models=self.capabilities.supported_models,
price_per_hour=price_per_hour,
availability_schedule=availability_schedule,
max_concurrent_jobs=max_concurrent_jobs
)
# Submit to marketplace
await self._submit_to_marketplace(offer)
self.current_offers.append(offer)
print(f"Resource offer submitted: {price_per_hour} AITBC/hour")
return True
except Exception as e:
print(f"Failed to offer resources: {e}")
return False
async def set_availability(self, schedule: Dict[str, Any]) -> bool:
"""Set availability schedule for resource offerings"""
try:
# Update all current offers with new schedule
for offer in self.current_offers:
offer.availability_schedule = schedule
await self._update_marketplace_offer(offer)
print("Availability schedule updated")
return True
except Exception as e:
print(f"Failed to update availability: {e}")
return False
async def enable_dynamic_pricing(self, base_rate: float, demand_threshold: float = 0.8, max_multiplier: float = 2.0, adjustment_frequency: str = "15min") -> bool:
"""Enable dynamic pricing based on market demand"""
try:
self.dynamic_pricing = {
"base_rate": base_rate,
"demand_threshold": demand_threshold,
"max_multiplier": max_multiplier,
"adjustment_frequency": adjustment_frequency,
"enabled": True
}
# Start dynamic pricing task
asyncio.create_task(self._dynamic_pricing_loop())
print("Dynamic pricing enabled")
return True
except Exception as e:
print(f"Failed to enable dynamic pricing: {e}")
return False
async def _dynamic_pricing_loop(self):
"""Background task for dynamic price adjustments"""
while getattr(self, 'dynamic_pricing', {}).get('enabled', False):
try:
# Get current utilization
current_utilization = len(self.active_jobs) / self.capabilities.max_concurrent_jobs
# Adjust pricing based on demand
if current_utilization > self.dynamic_pricing['demand_threshold']:
# High demand - increase price
multiplier = min(
1.0 + (current_utilization - self.dynamic_pricing['demand_threshold']) * 2,
self.dynamic_pricing['max_multiplier']
)
else:
# Low demand - decrease price
multiplier = max(0.5, current_utilization / self.dynamic_pricing['demand_threshold'])
new_price = self.dynamic_pricing['base_rate'] * multiplier
# Update marketplace offers
for offer in self.current_offers:
offer.price_per_hour = new_price
await self._update_marketplace_offer(offer)
print(f"Dynamic pricing: utilization={current_utilization:.2f}, price={new_price:.3f} AITBC/h")
except Exception as e:
print(f"Dynamic pricing error: {e}")
# Wait for next adjustment
await asyncio.sleep(900) # 15 minutes
async def accept_job(self, job_request: Dict[str, Any]) -> bool:
"""Accept and execute a computational job"""
try:
# Check capacity
if len(self.active_jobs) >= self.capabilities.max_concurrent_jobs:
return False
# Create job execution record
job = JobExecution(
job_id=job_request["job_id"],
consumer_id=job_request["consumer_id"],
start_time=datetime.utcnow(),
expected_duration=timedelta(hours=job_request["estimated_hours"])
)
self.active_jobs.append(job)
self._update_utilization()
# Execute job (simulate)
asyncio.create_task(self._execute_job(job, job_request))
print(f"Job accepted: {job.job_id} from {job.consumer_id}")
return True
except Exception as e:
print(f"Failed to accept job: {e}")
return False
async def _execute_job(self, job: JobExecution, job_request: Dict[str, Any]):
"""Execute a computational job"""
try:
# Simulate job execution
execution_time = timedelta(hours=job_request["estimated_hours"])
await asyncio.sleep(5) # Simulate processing time
# Update job completion
job.actual_duration = execution_time
job.status = "completed"
job.quality_score = 0.95 # Simulate quality score
# Calculate earnings
earnings = job_request["estimated_hours"] * job_request["agreed_price"]
self.earnings += earnings
# Remove from active jobs
self.active_jobs.remove(job)
self._update_utilization()
# Notify consumer
await self._notify_job_completion(job, earnings)
print(f"Job completed: {job.job_id}, earned {earnings} AITBC")
except Exception as e:
job.status = "failed"
print(f"Job execution failed: {job.job_id} - {e}")
async def _notify_job_completion(self, job: JobExecution, earnings: float):
"""Notify consumer about job completion"""
notification = {
"job_id": job.job_id,
"status": job.status,
"completion_time": datetime.utcnow().isoformat(),
"duration_hours": job.actual_duration.total_seconds() / 3600 if job.actual_duration else None,
"quality_score": job.quality_score,
"cost": earnings
}
await self.send_message(job.consumer_id, "job_completion", notification)
def _update_utilization(self):
"""Update current utilization rate"""
self.utilization_rate = len(self.active_jobs) / self.capabilities.max_concurrent_jobs
async def get_performance_metrics(self) -> Dict[str, Any]:
"""Get provider performance metrics"""
completed_jobs = [j for j in self.active_jobs if j.status == "completed"]
return {
"utilization_rate": self.utilization_rate,
"active_jobs": len(self.active_jobs),
"total_earnings": self.earnings,
"average_job_duration": sum(j.actual_duration.total_seconds() for j in completed_jobs) / len(completed_jobs) if completed_jobs else 0,
"quality_score": sum(j.quality_score for j in completed_jobs if j.quality_score) / len(completed_jobs) if completed_jobs else 0,
"current_offers": len(self.current_offers)
}
async def _submit_to_marketplace(self, offer: ResourceOffer):
"""Submit resource offer to marketplace (placeholder)"""
# TODO: Implement actual marketplace submission
await asyncio.sleep(0.1)
async def _update_marketplace_offer(self, offer: ResourceOffer):
"""Update existing marketplace offer (placeholder)"""
# TODO: Implement actual marketplace update
await asyncio.sleep(0.1)
@classmethod
def assess_capabilities(cls) -> Dict[str, Any]:
"""Assess available computational capabilities"""
# TODO: Implement actual capability assessment
return {
"gpu_memory": 24,
"supported_models": ["llama3.2", "mistral", "deepseek"],
"performance_score": 0.95,
"max_concurrent_jobs": 3
}

View File

@@ -0,0 +1,337 @@
"""
Swarm Coordinator - for agents participating in collective intelligence
"""
import asyncio
import json
from typing import Dict, List, Optional, Any
from datetime import datetime
from dataclasses import dataclass
from .agent import Agent
@dataclass
class SwarmMessage:
"""Swarm communication message"""
swarm_id: str
sender_id: str
message_type: str
priority: str
payload: Dict[str, Any]
timestamp: str
swarm_signature: str
@dataclass
class SwarmDecision:
"""Collective swarm decision"""
swarm_id: str
decision_type: str
proposal: Dict[str, Any]
votes: Dict[str, str] # agent_id -> vote
consensus: bool
implementation_plan: Dict[str, Any]
timestamp: str
class SwarmCoordinator(Agent):
"""Agent that participates in swarm intelligence"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.joined_swarms: Dict[str, Dict[str, Any]] = {}
self.swarm_reputation: Dict[str, float] = {}
self.contribution_score = 0.0
async def join_swarm(self, swarm_type: str, config: Dict[str, Any]) -> bool:
"""Join a swarm for collective intelligence"""
try:
swarm_id = f"{swarm_type}-v1"
# Register with swarm
registration = {
"agent_id": self.identity.id,
"swarm_id": swarm_id,
"role": config.get("role", "participant"),
"capabilities": {
"compute_type": self.capabilities.compute_type,
"performance_score": self.capabilities.performance_score,
"specialization": self.capabilities.specialization
},
"contribution_level": config.get("contribution_level", "medium"),
"data_sharing_consent": config.get("data_sharing_consent", True)
}
# Sign swarm registration
signature = self.identity.sign_message(registration)
registration["signature"] = signature
# Submit to swarm coordinator
await self._register_with_swarm(swarm_id, registration)
# Store swarm membership
self.joined_swarms[swarm_id] = {
"type": swarm_type,
"role": config.get("role", "participant"),
"joined_at": datetime.utcnow().isoformat(),
"contribution_count": 0,
"last_activity": datetime.utcnow().isoformat()
}
# Initialize swarm reputation
self.swarm_reputation[swarm_id] = 0.5 # Starting reputation
# Start swarm participation tasks
asyncio.create_task(self._swarm_participation_loop(swarm_id))
print(f"Joined swarm: {swarm_id} as {config.get('role', 'participant')}")
return True
except Exception as e:
print(f"Failed to join swarm {swarm_type}: {e}")
return False
async def _swarm_participation_loop(self, swarm_id: str):
"""Background task for active swarm participation"""
while swarm_id in self.joined_swarms:
try:
# Listen for swarm messages
await self._process_swarm_messages(swarm_id)
# Contribute data if enabled
swarm_config = self.joined_swarms[swarm_id]
if swarm_config.get("data_sharing", True):
await self._contribute_swarm_data(swarm_id)
# Participate in collective decisions
await self._participate_in_decisions(swarm_id)
# Update activity timestamp
swarm_config["last_activity"] = datetime.utcnow().isoformat()
except Exception as e:
print(f"Swarm participation error for {swarm_id}: {e}")
# Wait before next participation cycle
await asyncio.sleep(60) # 1 minute
async def broadcast_to_swarm(self, message: SwarmMessage) -> bool:
"""Broadcast a message to the swarm"""
try:
# Verify swarm membership
if message.swarm_id not in self.joined_swarms:
return False
# Sign swarm message
swarm_signature = self.identity.sign_message({
"swarm_id": message.swarm_id,
"sender_id": message.sender_id,
"message_type": message.message_type,
"payload": message.payload,
"timestamp": message.timestamp
})
message.swarm_signature = swarm_signature
# Broadcast to swarm network
await self._broadcast_to_swarm_network(message)
# Update contribution count
self.joined_swarms[message.swarm_id]["contribution_count"] += 1
print(f"Broadcasted to swarm {message.swarm_id}: {message.message_type}")
return True
except Exception as e:
print(f"Failed to broadcast to swarm: {e}")
return False
async def _contribute_swarm_data(self, swarm_id: str):
"""Contribute data to swarm intelligence"""
try:
swarm_type = self.joined_swarms[swarm_id]["type"]
if swarm_type == "load_balancing":
data = await self._get_load_balancing_data()
elif swarm_type == "pricing":
data = await self._get_pricing_data()
elif swarm_type == "security":
data = await self._get_security_data()
else:
data = await self._get_general_data()
message = SwarmMessage(
swarm_id=swarm_id,
sender_id=self.identity.id,
message_type="data_contribution",
priority="medium",
payload=data,
timestamp=datetime.utcnow().isoformat(),
swarm_signature="" # Will be added in broadcast_to_swarm
)
await self.broadcast_to_swarm(message)
except Exception as e:
print(f"Failed to contribute swarm data: {e}")
async def _get_load_balancing_data(self) -> Dict[str, Any]:
"""Get load balancing data for swarm contribution"""
# TODO: Get actual load balancing metrics
return {
"resource_type": "gpu_memory",
"availability": 0.75,
"location": "us-west-2",
"pricing_trend": "stable",
"current_load": 0.6,
"capacity_utilization": 0.8
}
async def _get_pricing_data(self) -> Dict[str, Any]:
"""Get pricing data for swarm contribution"""
# TODO: Get actual pricing data
return {
"current_demand": "high",
"price_trends": "increasing",
"resource_constraints": "gpu_memory",
"competitive_landscape": "moderate",
"market_volatility": 0.15
}
async def _get_security_data(self) -> Dict[str, Any]:
"""Get security data for swarm contribution"""
# TODO: Get actual security metrics
return {
"threat_level": "low",
"anomaly_count": 2,
"verification_success_rate": 0.98,
"network_health": "good",
"security_events": []
}
async def _get_general_data(self) -> Dict[str, Any]:
"""Get general performance data for swarm contribution"""
return {
"performance_metrics": {
"response_time": 30.5,
"success_rate": 0.95,
"quality_score": 0.92
},
"network_status": "healthy",
"agent_status": "active"
}
async def coordinate_task(self, task: str, collaborators: int) -> Dict[str, Any]:
"""Coordinate a collaborative task with other agents"""
try:
# Create coordination proposal
proposal = {
"task_id": f"task_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}",
"task_type": task,
"coordinator_id": self.identity.id,
"required_collaborators": collaborators,
"task_description": f"Collaborative {task} task",
"estimated_duration": "2h",
"resource_requirements": {
"compute_type": "general",
"min_performance": 0.8
}
}
# Submit to swarm for coordination
coordination_result = await self._submit_coordination_proposal(proposal)
print(f"Task coordination initiated: {task} with {collaborators} collaborators")
return coordination_result
except Exception as e:
print(f"Failed to coordinate task: {e}")
return {"success": False, "error": str(e)}
async def get_market_intelligence(self) -> Dict[str, Any]:
"""Get collective market intelligence from swarm"""
try:
# Request market intelligence from pricing swarm
if "pricing-v1" in self.joined_swarms:
intel_request = SwarmMessage(
swarm_id="pricing-v1",
sender_id=self.identity.id,
message_type="intelligence_request",
priority="high",
payload={"request_type": "market_intelligence"},
timestamp=datetime.utcnow().isoformat(),
swarm_signature=""
)
await self.broadcast_to_swarm(intel_request)
# Wait for intelligence response (simulate)
await asyncio.sleep(2)
return {
"demand_forecast": "increasing",
"price_trends": "stable_to_rising",
"competition_analysis": "moderate",
"opportunity_areas": ["specialized_models", "batch_processing"],
"risk_factors": ["gpu_shortages", "price_volatility"]
}
else:
return {"error": "Not joined to pricing swarm"}
except Exception as e:
print(f"Failed to get market intelligence: {e}")
return {"error": str(e)}
async def analyze_swarm_benefits(self) -> Dict[str, Any]:
"""Analyze benefits of swarm participation"""
try:
# Calculate benefits based on swarm participation
total_contributions = sum(
swarm["contribution_count"]
for swarm in self.joined_swarms.values()
)
avg_reputation = sum(self.swarm_reputation.values()) / len(self.swarm_reputation) if self.swarm_reputation else 0
# Simulate benefit analysis
earnings_boost = total_contributions * 0.15 # 15% boost per contribution
utilization_improvement = avg_reputation * 0.25 # 25% utilization improvement
return {
"earnings_boost": f"{earnings_boost:.1%}",
"utilization_improvement": f"{utilization_improvement:.1%}",
"total_contributions": total_contributions,
"swarm_reputation": avg_reputation,
"joined_swarms": len(self.joined_swarms)
}
except Exception as e:
print(f"Failed to analyze swarm benefits: {e}")
return {"error": str(e)}
async def _register_with_swarm(self, swarm_id: str, registration: Dict[str, Any]):
"""Register with swarm coordinator (placeholder)"""
# TODO: Implement actual swarm registration
await asyncio.sleep(0.1)
async def _broadcast_to_swarm_network(self, message: SwarmMessage):
"""Broadcast message to swarm network (placeholder)"""
# TODO: Implement actual swarm broadcasting
await asyncio.sleep(0.1)
async def _process_swarm_messages(self, swarm_id: str):
"""Process incoming swarm messages (placeholder)"""
# TODO: Implement actual message processing
await asyncio.sleep(0.1)
async def _participate_in_decisions(self, swarm_id: str):
"""Participate in swarm decision making (placeholder)"""
# TODO: Implement actual decision participation
await asyncio.sleep(0.1)
async def _submit_coordination_proposal(self, proposal: Dict[str, Any]) -> Dict[str, Any]:
"""Submit coordination proposal to swarm (placeholder)"""
# TODO: Implement actual proposal submission
await asyncio.sleep(0.5)
return {
"success": True,
"proposal_id": proposal["task_id"],
"status": "coordinating",
"expected_collaborators": 5
}

View File

@@ -146,9 +146,29 @@ pytest tests/security/
## Dependencies
- **pynacl**: Cryptographic primitives (Ed25519, X25519)
- **pydantic**: Data validation and serialization
- **Dependencies**: pynacl>=1.5.0, pydantic>=2.0.0
- **Python 3.11+**: Modern Python features and performance
## Compatibility & Stability
### Python Version Support
- **Minimum Version**: Python 3.11+
- **Recommended**: Python 3.11 or 3.12
- **Security Guarantee**: All cryptographic operations maintain security properties
- **Performance**: Optimized for Python 3.11+ performance improvements
### Cryptographic Security
- **Algorithm**: Ed25519 digital signatures (constant-time implementation)
- **Key Security**: 256-bit keys with proper entropy requirements
- **Signature Verification**: Timing-attack resistant verification
- **Randomness**: Uses cryptographically secure random number generation
### API Stability
- **Major Version**: 0.x (pre-1.0, APIs may evolve)
- **Backward Compatibility**: Maintained within Python 3.11+ versions
- **Security Updates**: Non-breaking security improvements may be added
- **Deprecation Notice**: 2+ releases for deprecated cryptographic features
## License
MIT License - see LICENSE file for details.

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
description = "AITBC cryptographic utilities for zero-knowledge proofs and digital signatures"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.11"
requires-python = ">=3.13"
authors = [
{name = "AITBC Team", email = "team@aitbc.dev"}
]
@@ -16,6 +16,7 @@ classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Security :: Cryptography",
"Topic :: Software Development :: Libraries :: Python Modules"
]

View File

@@ -15,9 +15,10 @@ Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Python: >=3.13
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.7.0
Requires-Dist: pynacl>=1.5.0
@@ -176,9 +177,29 @@ pytest tests/security/
## Dependencies
- **pynacl**: Cryptographic primitives (Ed25519, X25519)
- **pydantic**: Data validation and serialization
- **Dependencies**: pynacl>=1.5.0, pydantic>=2.0.0
- **Python 3.11+**: Modern Python features and performance
## Compatibility & Stability
### Python Version Support
- **Minimum Version**: Python 3.11+
- **Recommended**: Python 3.11 or 3.12
- **Security Guarantee**: All cryptographic operations maintain security properties
- **Performance**: Optimized for Python 3.11+ performance improvements
### Cryptographic Security
- **Algorithm**: Ed25519 digital signatures (constant-time implementation)
- **Key Security**: 256-bit keys with proper entropy requirements
- **Signature Verification**: Timing-attack resistant verification
- **Randomness**: Uses cryptographically secure random number generation
### API Stability
- **Major Version**: 0.x (pre-1.0, APIs may evolve)
- **Backward Compatibility**: Maintained within Python 3.11+ versions
- **Security Updates**: Non-breaking security improvements may be added
- **Deprecation Notice**: 2+ releases for deprecated cryptographic features
## License
MIT License - see LICENSE file for details.

View File

@@ -8,6 +8,25 @@ Python client SDK for interacting with AITBC coordinator services, blockchain no
pip install aitbc-sdk
```
## Requirements
- **Python**: 3.11 or later
- **Dependencies**: httpx, pydantic, aitbc-crypto
## Compatibility & Stability
### Python Version Support
- **Minimum Version**: Python 3.11+
- **Recommended**: Python 3.11 or 3.12
- **Guarantee**: All APIs maintain backward compatibility within Python 3.11+
- **Security**: Cryptographic operations maintain security properties across versions
### API Stability
- **Major Version**: 0.x (pre-1.0, APIs may change with notice)
- **Deprecation Policy**: Deprecated features marked with warnings for 2+ releases
- **Breaking Changes**: Announced in release notes with migration guides
- **Semantic Versioning**: Follows semver.org specifications
## Quick Start
```python

View File

@@ -4,7 +4,7 @@ version = "0.1.0"
description = "AITBC client SDK for interacting with coordinator services"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.11"
requires-python = ">=3.13"
authors = [
{name = "AITBC Team", email = "team@aitbc.dev"}
]
@@ -16,6 +16,7 @@ classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Scientific/Engineering :: Artificial Intelligence"
]

View File

@@ -15,9 +15,10 @@ Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Requires-Python: >=3.13
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.7.0
@@ -39,6 +40,25 @@ Python client SDK for interacting with AITBC coordinator services, blockchain no
pip install aitbc-sdk
```
## Requirements
- **Python**: 3.11 or later
- **Dependencies**: httpx, pydantic, aitbc-crypto
## Compatibility & Stability
### Python Version Support
- **Minimum Version**: Python 3.11+
- **Recommended**: Python 3.11 or 3.12
- **Guarantee**: All APIs maintain backward compatibility within Python 3.11+
- **Security**: Cryptographic operations maintain security properties across versions
### API Stability
- **Major Version**: 0.x (pre-1.0, APIs may change with notice)
- **Deprecation Policy**: Deprecated features marked with warnings for 2+ releases
- **Breaking Changes**: Announced in release notes with migration guides
- **Semantic Versioning**: Follows semver.org specifications
## Quick Start
```python

View File

@@ -123,6 +123,42 @@
"ERC20"
]
},
"/home/oib/windsurf/aitbc/packages/solidity/aitbc-token/node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
"lastModificationDate": 1758948616491,
"contentHash": "81de029d56aa803972be03c5d277cb6c",
"sourceName": "@openzeppelin/contracts/utils/cryptography/ECDSA.sol",
"solcConfig": {
"version": "0.8.24",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.20"
],
"artifacts": [
"ECDSA"
]
},
"/home/oib/windsurf/aitbc/packages/solidity/aitbc-token/node_modules/@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol": {
"lastModificationDate": 1758948616595,
"contentHash": "260f3968eefa3bbd30520cff5384cd93",
@@ -161,42 +197,6 @@
"MessageHashUtils"
]
},
"/home/oib/windsurf/aitbc/packages/solidity/aitbc-token/node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
"lastModificationDate": 1758948616491,
"contentHash": "81de029d56aa803972be03c5d277cb6c",
"sourceName": "@openzeppelin/contracts/utils/cryptography/ECDSA.sol",
"solcConfig": {
"version": "0.8.24",
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
}
}
},
"imports": [],
"versionPragmas": [
"^0.8.20"
],
"artifacts": [
"ECDSA"
]
},
"/home/oib/windsurf/aitbc/packages/solidity/aitbc-token/node_modules/@openzeppelin/contracts/access/IAccessControl.sol": {
"lastModificationDate": 1758948616567,
"contentHash": "def1e8f7b6cac577cf2600655bf3bdf8",