Major WHOOSH system refactoring and feature enhancements
- Migrated from HIVE branding to WHOOSH across all components - Enhanced backend API with new services: AI models, BZZZ integration, templates, members - Added comprehensive testing suite with security, performance, and integration tests - Improved frontend with new components for project setup, AI models, and team management - Updated MCP server implementation with WHOOSH-specific tools and resources - Enhanced deployment configurations with production-ready Docker setups - Added comprehensive documentation and setup guides - Implemented age encryption service and UCXL integration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
266
backend/app/api/bzzz_integration.py
Normal file
266
backend/app/api/bzzz_integration.py
Normal file
@@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
BZZZ Integration API for WHOOSH
|
||||
API endpoints for team collaboration, decision publishing, and consensus mechanisms
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends, Query
|
||||
from typing import Dict, List, Optional, Any
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
|
||||
from ..services.bzzz_integration_service import bzzz_service, AgentRole
|
||||
from ..core.auth_deps import get_current_user
|
||||
from ..models.user import User
|
||||
|
||||
router = APIRouter(prefix="/api/bzzz", tags=["BZZZ Integration"])
|
||||
|
||||
# Pydantic models for API requests/responses
|
||||
|
||||
class DecisionRequest(BaseModel):
|
||||
title: str = Field(..., description="Decision title")
|
||||
description: str = Field(..., description="Detailed decision description")
|
||||
context: Dict[str, Any] = Field(default_factory=dict, description="Decision context data")
|
||||
ucxl_address: Optional[str] = Field(None, description="Related UCXL address")
|
||||
|
||||
class DecisionResponse(BaseModel):
|
||||
decision_id: str
|
||||
title: str
|
||||
description: str
|
||||
author_role: str
|
||||
timestamp: datetime
|
||||
ucxl_address: Optional[str] = None
|
||||
|
||||
class TaskAssignmentRequest(BaseModel):
|
||||
task_description: str = Field(..., description="Task description")
|
||||
required_capabilities: List[str] = Field(..., description="Required capabilities")
|
||||
priority: str = Field("medium", description="Task priority (low, medium, high, urgent)")
|
||||
|
||||
class TaskAssignmentResponse(BaseModel):
|
||||
decision_id: Optional[str]
|
||||
assigned_to: str
|
||||
assignment_score: float
|
||||
alternatives: List[Dict[str, Any]]
|
||||
|
||||
class TeamMemberInfo(BaseModel):
|
||||
agent_id: str
|
||||
role: str
|
||||
endpoint: str
|
||||
capabilities: List[str]
|
||||
status: str
|
||||
|
||||
class TeamStatusResponse(BaseModel):
|
||||
total_members: int
|
||||
online_members: int
|
||||
offline_members: int
|
||||
role_distribution: Dict[str, int]
|
||||
active_decisions: int
|
||||
recent_decisions: List[Dict[str, Any]]
|
||||
network_health: float
|
||||
|
||||
class ConsensusResponse(BaseModel):
|
||||
decision_id: str
|
||||
total_votes: int
|
||||
approvals: int
|
||||
approval_rate: float
|
||||
consensus_reached: bool
|
||||
details: Dict[str, Any]
|
||||
|
||||
@router.get("/status", response_model=TeamStatusResponse)
|
||||
async def get_team_status(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> TeamStatusResponse:
|
||||
"""Get current BZZZ team status and network health"""
|
||||
try:
|
||||
status = await bzzz_service.get_team_status()
|
||||
return TeamStatusResponse(**status)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get team status: {str(e)}")
|
||||
|
||||
@router.get("/members", response_model=List[TeamMemberInfo])
|
||||
async def get_team_members(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> List[TeamMemberInfo]:
|
||||
"""Get list of active team members in BZZZ network"""
|
||||
try:
|
||||
members = []
|
||||
for member in bzzz_service.team_members.values():
|
||||
members.append(TeamMemberInfo(
|
||||
agent_id=member.agent_id,
|
||||
role=member.role.value,
|
||||
endpoint=member.endpoint,
|
||||
capabilities=member.capabilities,
|
||||
status=member.status
|
||||
))
|
||||
return members
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get team members: {str(e)}")
|
||||
|
||||
@router.post("/decisions", response_model=Dict[str, str])
|
||||
async def publish_decision(
|
||||
decision: DecisionRequest,
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> Dict[str, str]:
|
||||
"""
|
||||
Publish a decision to the BZZZ network for team consensus
|
||||
"""
|
||||
try:
|
||||
decision_id = await bzzz_service.publish_decision(
|
||||
title=decision.title,
|
||||
description=decision.description,
|
||||
context=decision.context,
|
||||
ucxl_address=decision.ucxl_address
|
||||
)
|
||||
|
||||
if decision_id:
|
||||
return {"decision_id": decision_id, "status": "published"}
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail="Failed to publish decision")
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to publish decision: {str(e)}")
|
||||
|
||||
@router.get("/decisions", response_model=List[DecisionResponse])
|
||||
async def get_recent_decisions(
|
||||
limit: int = Query(10, ge=1, le=100),
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> List[DecisionResponse]:
|
||||
"""Get recent decisions from BZZZ network"""
|
||||
try:
|
||||
decisions = sorted(
|
||||
bzzz_service.active_decisions.values(),
|
||||
key=lambda d: d.timestamp,
|
||||
reverse=True
|
||||
)[:limit]
|
||||
|
||||
return [
|
||||
DecisionResponse(
|
||||
decision_id=decision.id,
|
||||
title=decision.title,
|
||||
description=decision.description,
|
||||
author_role=decision.author_role,
|
||||
timestamp=decision.timestamp,
|
||||
ucxl_address=decision.ucxl_address
|
||||
)
|
||||
for decision in decisions
|
||||
]
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get decisions: {str(e)}")
|
||||
|
||||
@router.get("/decisions/{decision_id}/consensus", response_model=Optional[ConsensusResponse])
|
||||
async def get_decision_consensus(
|
||||
decision_id: str,
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> Optional[ConsensusResponse]:
|
||||
"""Get consensus status for a specific decision"""
|
||||
try:
|
||||
consensus = await bzzz_service.get_team_consensus(decision_id)
|
||||
|
||||
if consensus:
|
||||
return ConsensusResponse(**consensus)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="Decision not found or no consensus data available")
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get consensus: {str(e)}")
|
||||
|
||||
@router.post("/tasks/assign", response_model=TaskAssignmentResponse)
|
||||
async def coordinate_task_assignment(
|
||||
task: TaskAssignmentRequest,
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> TaskAssignmentResponse:
|
||||
"""
|
||||
Coordinate task assignment across team members based on capabilities and availability
|
||||
"""
|
||||
try:
|
||||
assignment = await bzzz_service.coordinate_task_assignment(
|
||||
task_description=task.task_description,
|
||||
required_capabilities=task.required_capabilities,
|
||||
priority=task.priority
|
||||
)
|
||||
|
||||
if assignment:
|
||||
return TaskAssignmentResponse(**assignment)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="No suitable team members found for task")
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to coordinate task assignment: {str(e)}")
|
||||
|
||||
@router.post("/network/discover")
|
||||
async def rediscover_network(
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> Dict[str, Any]:
|
||||
"""Manually trigger team member discovery"""
|
||||
try:
|
||||
await bzzz_service._discover_team_members()
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"members_discovered": len(bzzz_service.team_members),
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to rediscover network: {str(e)}")
|
||||
|
||||
@router.get("/roles", response_model=List[str])
|
||||
async def get_available_roles() -> List[str]:
|
||||
"""Get list of available agent roles in BZZZ system"""
|
||||
return [role.value for role in AgentRole]
|
||||
|
||||
@router.get("/capabilities/{agent_id}", response_model=Dict[str, Any])
|
||||
async def get_agent_capabilities(
|
||||
agent_id: str,
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> Dict[str, Any]:
|
||||
"""Get detailed capabilities of a specific team member"""
|
||||
try:
|
||||
if agent_id not in bzzz_service.team_members:
|
||||
raise HTTPException(status_code=404, detail=f"Agent {agent_id} not found")
|
||||
|
||||
member = bzzz_service.team_members[agent_id]
|
||||
|
||||
return {
|
||||
"agent_id": member.agent_id,
|
||||
"role": member.role.value,
|
||||
"capabilities": member.capabilities,
|
||||
"status": member.status,
|
||||
"endpoint": member.endpoint,
|
||||
"last_seen": datetime.utcnow().isoformat() # Placeholder
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get agent capabilities: {str(e)}")
|
||||
|
||||
@router.get("/health")
|
||||
async def bzzz_health_check() -> Dict[str, Any]:
|
||||
"""BZZZ integration health check endpoint"""
|
||||
try:
|
||||
total_members = len(bzzz_service.team_members)
|
||||
online_members = sum(1 for m in bzzz_service.team_members.values() if m.status == "online")
|
||||
|
||||
health_status = "healthy" if online_members >= total_members * 0.5 else "degraded"
|
||||
if online_members == 0:
|
||||
health_status = "offline"
|
||||
|
||||
return {
|
||||
"status": health_status,
|
||||
"bzzz_endpoints": len(bzzz_service.bzzz_endpoints),
|
||||
"team_members": total_members,
|
||||
"online_members": online_members,
|
||||
"active_decisions": len(bzzz_service.active_decisions),
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"status": "error",
|
||||
"error": str(e),
|
||||
"timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
# Note: Exception handlers are registered at the app level, not router level
|
||||
Reference in New Issue
Block a user