Integrate Bzzz P2P task coordination and enhance project management
🔗 Bzzz Integration: - Added comprehensive Bzzz integration documentation and todos - Implemented N8N chat workflow architecture for task coordination - Enhanced project management with Bzzz-specific features - Added GitHub service for seamless issue synchronization - Created BzzzIntegration component for frontend management 🎯 Project Management Enhancements: - Improved project listing and filtering capabilities - Enhanced authentication and authorization flows - Added unified coordinator for better task orchestration - Streamlined project activation and configuration - Updated API endpoints for Bzzz compatibility 📊 Technical Improvements: - Updated Docker Swarm configuration for local registry - Enhanced frontend build with updated assets - Improved WebSocket connections for real-time updates - Added comprehensive error handling and logging - Updated environment configurations for production ✅ System Integration: - Successfully tested with Bzzz v1.2 task execution workflow - Validated GitHub issue discovery and claiming functionality - Confirmed sandbox-based task execution compatibility - Verified Docker registry integration This release enables seamless integration between Hive project management and Bzzz P2P task coordination, creating a complete distributed development ecosystem. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,7 @@ Key Features:
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request, Depends, status
|
||||
from typing import List, Dict, Any
|
||||
from ..core.unified_coordinator import Agent, AgentType
|
||||
from ..models.agent import Agent
|
||||
from ..models.responses import (
|
||||
AgentListResponse,
|
||||
AgentRegistrationResponse,
|
||||
|
||||
@@ -157,6 +157,28 @@ async def login(
|
||||
|
||||
token_response = create_token_response(user.id, user_data)
|
||||
|
||||
# Create UserResponse object for proper serialization
|
||||
user_response = UserResponse(
|
||||
id=user_data["id"],
|
||||
username=user_data["username"],
|
||||
email=user_data["email"],
|
||||
full_name=user_data["full_name"],
|
||||
is_active=user_data["is_active"],
|
||||
is_superuser=user_data["is_superuser"],
|
||||
is_verified=user_data["is_verified"],
|
||||
created_at=user_data["created_at"],
|
||||
last_login=user_data["last_login"]
|
||||
)
|
||||
|
||||
# Create final response manually to avoid datetime serialization issues
|
||||
final_response = TokenResponse(
|
||||
access_token=token_response["access_token"],
|
||||
refresh_token=token_response["refresh_token"],
|
||||
token_type=token_response["token_type"],
|
||||
expires_in=token_response["expires_in"],
|
||||
user=user_response
|
||||
)
|
||||
|
||||
# Store refresh token in database
|
||||
refresh_token_plain = token_response["refresh_token"]
|
||||
refresh_token_hash = User.hash_password(refresh_token_plain)
|
||||
@@ -179,7 +201,7 @@ async def login(
|
||||
db.add(refresh_token_record)
|
||||
db.commit()
|
||||
|
||||
return TokenResponse(**token_response)
|
||||
return final_response
|
||||
|
||||
|
||||
@router.post("/refresh", response_model=TokenResponse)
|
||||
@@ -230,7 +252,28 @@ async def refresh_token(
|
||||
user_data = user.to_dict()
|
||||
user_data["scopes"] = ["admin"] if user.is_superuser else []
|
||||
|
||||
return TokenResponse(**create_token_response(user.id, user_data))
|
||||
token_response = create_token_response(user.id, user_data)
|
||||
|
||||
# Create UserResponse object for proper serialization
|
||||
user_response = UserResponse(
|
||||
id=user_data["id"],
|
||||
username=user_data["username"],
|
||||
email=user_data["email"],
|
||||
full_name=user_data["full_name"],
|
||||
is_active=user_data["is_active"],
|
||||
is_superuser=user_data["is_superuser"],
|
||||
is_verified=user_data["is_verified"],
|
||||
created_at=user_data["created_at"],
|
||||
last_login=user_data["last_login"]
|
||||
)
|
||||
|
||||
return TokenResponse(
|
||||
access_token=token_response["access_token"],
|
||||
refresh_token=token_response["refresh_token"],
|
||||
token_type=token_response["token_type"],
|
||||
expires_in=token_response["expires_in"],
|
||||
user=user_response
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
|
||||
@@ -9,7 +9,7 @@ from fastapi import APIRouter, HTTPException, Request, Depends, status
|
||||
from typing import List, Dict, Any, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from ..services.capability_detector import CapabilityDetector, detect_capabilities
|
||||
from ..core.unified_coordinator import Agent, AgentType
|
||||
# Agent model is imported as ORMAgent below
|
||||
from ..models.responses import (
|
||||
AgentListResponse,
|
||||
AgentRegistrationResponse,
|
||||
|
||||
@@ -20,7 +20,7 @@ from datetime import datetime
|
||||
|
||||
from ..core.database import get_db
|
||||
from ..models.agent import Agent as ORMAgent
|
||||
from ..core.unified_coordinator import UnifiedCoordinator, Agent, AgentType
|
||||
from ..core.unified_coordinator_refactored import UnifiedCoordinatorRefactored as UnifiedCoordinator
|
||||
from ..cli_agents.cli_agent_manager import get_cli_agent_manager
|
||||
from ..models.responses import (
|
||||
CliAgentListResponse,
|
||||
|
||||
@@ -6,6 +6,9 @@ from app.services.project_service import ProjectService
|
||||
router = APIRouter()
|
||||
project_service = ProjectService()
|
||||
|
||||
# Bzzz Integration Router
|
||||
bzzz_router = APIRouter(prefix="/bzzz", tags=["bzzz-integration"])
|
||||
|
||||
@router.get("/projects")
|
||||
async def get_projects(current_user: Dict[str, Any] = Depends(get_current_user_context)) -> List[Dict[str, Any]]:
|
||||
"""Get all projects from the local filesystem."""
|
||||
@@ -41,5 +44,131 @@ async def get_project_tasks(project_id: str, current_user: Dict[str, Any] = Depe
|
||||
"""Get tasks for a project (from GitHub issues and TODOS.md)."""
|
||||
try:
|
||||
return project_service.get_project_tasks(project_id)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# === Bzzz Integration Endpoints ===
|
||||
|
||||
@bzzz_router.get("/active-repos")
|
||||
async def get_active_repositories() -> Dict[str, Any]:
|
||||
"""Get list of active repository configurations for Bzzz consumption."""
|
||||
try:
|
||||
active_repos = project_service.get_bzzz_active_repositories()
|
||||
return {"repositories": active_repos}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@bzzz_router.get("/projects/{project_id}/tasks")
|
||||
async def get_bzzz_project_tasks(project_id: str) -> List[Dict[str, Any]]:
|
||||
"""Get bzzz-task labeled issues for a specific project."""
|
||||
try:
|
||||
return project_service.get_bzzz_project_tasks(project_id)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@bzzz_router.post("/projects/{project_id}/claim")
|
||||
async def claim_bzzz_task(project_id: str, task_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Register task claim with Hive system."""
|
||||
try:
|
||||
task_number = task_data.get("task_number")
|
||||
agent_id = task_data.get("agent_id")
|
||||
|
||||
if not task_number or not agent_id:
|
||||
raise HTTPException(status_code=400, detail="task_number and agent_id are required")
|
||||
|
||||
result = project_service.claim_bzzz_task(project_id, task_number, agent_id)
|
||||
return {"success": True, "claim_id": result}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@bzzz_router.put("/projects/{project_id}/status")
|
||||
async def update_bzzz_task_status(project_id: str, status_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Update task status in Hive system."""
|
||||
try:
|
||||
task_number = status_data.get("task_number")
|
||||
status = status_data.get("status")
|
||||
metadata = status_data.get("metadata", {})
|
||||
|
||||
if not task_number or not status:
|
||||
raise HTTPException(status_code=400, detail="task_number and status are required")
|
||||
|
||||
project_service.update_bzzz_task_status(project_id, task_number, status, metadata)
|
||||
return {"success": True}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
# === Additional N8N Integration Endpoints ===
|
||||
|
||||
@bzzz_router.post("/chat-log")
|
||||
async def log_bzzz_chat(chat_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Log bzzz chat conversation for analytics and monitoring."""
|
||||
try:
|
||||
# Extract chat data
|
||||
session_id = chat_data.get("sessionId", "unknown")
|
||||
query = chat_data.get("query", "")
|
||||
response = chat_data.get("response", "")
|
||||
confidence = chat_data.get("confidence", 0)
|
||||
source_agents = chat_data.get("sourceAgents", [])
|
||||
timestamp = chat_data.get("timestamp", "")
|
||||
|
||||
# Log to file for now (could be database in future)
|
||||
import json
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
log_dir = "/tmp/bzzz_logs"
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
log_entry = {
|
||||
"session_id": session_id,
|
||||
"query": query,
|
||||
"response": response,
|
||||
"confidence": confidence,
|
||||
"source_agents": source_agents,
|
||||
"timestamp": timestamp,
|
||||
"logged_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
log_file = os.path.join(log_dir, f"chat_log_{datetime.now().strftime('%Y%m%d')}.jsonl")
|
||||
with open(log_file, "a") as f:
|
||||
f.write(json.dumps(log_entry) + "\n")
|
||||
|
||||
return {"success": True, "logged": True, "session_id": session_id}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@bzzz_router.post("/antennae-log")
|
||||
async def log_antennae_data(antennae_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Log antennae meta-thinking data for pattern analysis."""
|
||||
try:
|
||||
# Extract antennae monitoring data
|
||||
antennae_patterns = antennae_data.get("antennaeData", {})
|
||||
metrics = antennae_data.get("metrics", {})
|
||||
timestamp = antennae_data.get("timestamp", "")
|
||||
active_agents = antennae_data.get("activeAgents", 0)
|
||||
|
||||
# Log to file for now (could be database in future)
|
||||
import json
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
log_dir = "/tmp/bzzz_logs"
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
|
||||
log_entry = {
|
||||
"antennae_patterns": antennae_patterns,
|
||||
"metrics": metrics,
|
||||
"timestamp": timestamp,
|
||||
"active_agents": active_agents,
|
||||
"logged_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
log_file = os.path.join(log_dir, f"antennae_log_{datetime.now().strftime('%Y%m%d')}.jsonl")
|
||||
with open(log_file, "a") as f:
|
||||
f.write(json.dumps(log_entry) + "\n")
|
||||
|
||||
return {"success": True, "logged": True, "patterns_count": len(antennae_patterns.get("collaborationPatterns", []))}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user