GT AI OS Community v2.0.33 - Add NVIDIA NIM and Nemotron agents
- Updated python_coding_microproject.csv to use NVIDIA NIM Kimi K2 - Updated kali_linux_shell_simulator.csv to use NVIDIA NIM Kimi K2 - Made more general-purpose (flexible targets, expanded tools) - Added nemotron-mini-agent.csv for fast local inference via Ollama - Added nemotron-agent.csv for advanced reasoning via Ollama - Added wiki page: Projects for NVIDIA NIMs and Nemotron
This commit is contained in:
283
apps/resource-cluster/app/api/agents.py
Normal file
283
apps/resource-cluster/app/api/agents.py
Normal file
@@ -0,0 +1,283 @@
|
||||
"""
|
||||
Agent orchestration API endpoints
|
||||
|
||||
Provides endpoints for:
|
||||
- Individual agent execution by agent ID
|
||||
- Agent execution status tracking
|
||||
- workflows orchestration
|
||||
- Capability-based authentication for all operations
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends, Path
|
||||
from typing import Dict, Any, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import uuid
|
||||
import asyncio
|
||||
|
||||
from app.core.security import capability_validator, CapabilityToken
|
||||
from app.api.auth import verify_capability
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AgentExecutionRequest(BaseModel):
|
||||
"""Agent execution request for specific agent"""
|
||||
input_data: Dict[str, Any] = Field(..., description="Input data for the agent")
|
||||
parameters: Optional[Dict[str, Any]] = Field(default={}, description="Execution parameters")
|
||||
timeout_seconds: Optional[int] = Field(default=300, description="Execution timeout")
|
||||
priority: Optional[int] = Field(default=0, description="Execution priority")
|
||||
|
||||
|
||||
class AgentExecutionResponse(BaseModel):
|
||||
"""Agent execution response"""
|
||||
execution_id: str = Field(..., description="Unique execution identifier")
|
||||
agent_id: str = Field(..., description="Agent identifier")
|
||||
status: str = Field(..., description="Execution status")
|
||||
created_at: datetime = Field(..., description="Creation timestamp")
|
||||
|
||||
|
||||
class AgentExecutionStatus(BaseModel):
|
||||
"""Agent execution status"""
|
||||
execution_id: str = Field(..., description="Execution identifier")
|
||||
agent_id: str = Field(..., description="Agent identifier")
|
||||
status: str = Field(..., description="Current status")
|
||||
progress: Optional[float] = Field(default=None, description="Execution progress (0-100)")
|
||||
result: Optional[Dict[str, Any]] = Field(default=None, description="Execution result if completed")
|
||||
error: Optional[str] = Field(default=None, description="Error message if failed")
|
||||
created_at: datetime = Field(..., description="Creation timestamp")
|
||||
updated_at: datetime = Field(..., description="Last update timestamp")
|
||||
completed_at: Optional[datetime] = Field(default=None, description="Completion timestamp")
|
||||
|
||||
|
||||
# Global execution tracking
|
||||
_active_executions: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
|
||||
class AgentRequest(BaseModel):
|
||||
"""Legacy agent execution request for backward compatibility"""
|
||||
agent_type: str = Field(..., description="Type of agent to execute")
|
||||
task: str = Field(..., description="Task for the agent")
|
||||
context: Dict[str, Any] = Field(default={}, description="Additional context")
|
||||
|
||||
|
||||
@router.post("/execute")
|
||||
async def execute_agent(
|
||||
request: AgentRequest,
|
||||
token: CapabilityToken = Depends(verify_capability)
|
||||
) -> Dict[str, Any]:
|
||||
"""Execute an workflows"""
|
||||
|
||||
try:
|
||||
from app.services.agent_orchestrator import AgentOrchestrator
|
||||
|
||||
# Initialize orchestrator
|
||||
orchestrator = AgentOrchestrator()
|
||||
|
||||
# Create workflow based on request
|
||||
workflow_config = {
|
||||
"type": request.workflow_type or "sequential",
|
||||
"agents": request.agents,
|
||||
"input_data": request.input_data,
|
||||
"configuration": request.configuration or {}
|
||||
}
|
||||
|
||||
# Generate unique workflow ID
|
||||
import uuid
|
||||
workflow_id = f"workflow_{uuid.uuid4().hex[:8]}"
|
||||
|
||||
# Create and register workflow
|
||||
workflow = await orchestrator.create_workflow(workflow_id, workflow_config)
|
||||
|
||||
# Execute the workflow
|
||||
result = await orchestrator.execute_workflow(
|
||||
workflow_id=workflow_id,
|
||||
input_data=request.input_data,
|
||||
capability_token=token.token
|
||||
)
|
||||
|
||||
# codeql[py/stack-trace-exposure] returns workflow result dict, not error details
|
||||
return {
|
||||
"success": True,
|
||||
"workflow_id": workflow_id,
|
||||
"result": result,
|
||||
"execution_time": result.get("execution_time", 0)
|
||||
}
|
||||
|
||||
except ValueError as e:
|
||||
logger.warning(f"Invalid agent request: {e}")
|
||||
raise HTTPException(status_code=400, detail="Invalid request parameters")
|
||||
except Exception as e:
|
||||
logger.error(f"Agent execution failed: {e}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail="Agent execution failed")
|
||||
|
||||
|
||||
@router.post("/{agent_id}/execute", response_model=AgentExecutionResponse)
|
||||
async def execute_agent_by_id(
|
||||
agent_id: str = Path(..., description="Agent identifier"),
|
||||
request: AgentExecutionRequest = ...,
|
||||
token: CapabilityToken = Depends(verify_capability)
|
||||
) -> AgentExecutionResponse:
|
||||
"""Execute a specific agent by ID"""
|
||||
|
||||
try:
|
||||
# Generate unique execution ID
|
||||
execution_id = f"exec_{uuid.uuid4().hex[:12]}"
|
||||
|
||||
# Create execution record
|
||||
execution_data = {
|
||||
"execution_id": execution_id,
|
||||
"agent_id": agent_id,
|
||||
"status": "queued",
|
||||
"input_data": request.input_data,
|
||||
"parameters": request.parameters or {},
|
||||
"timeout_seconds": request.timeout_seconds,
|
||||
"priority": request.priority,
|
||||
"created_at": datetime.utcnow(),
|
||||
"updated_at": datetime.utcnow(),
|
||||
"token": token.token
|
||||
}
|
||||
|
||||
# Store execution
|
||||
_active_executions[execution_id] = execution_data
|
||||
|
||||
# Start async execution
|
||||
asyncio.create_task(_execute_agent_async(execution_id, agent_id, request, token))
|
||||
|
||||
logger.info(f"Started agent execution {execution_id} for agent {agent_id}")
|
||||
|
||||
return AgentExecutionResponse(
|
||||
execution_id=execution_id,
|
||||
agent_id=agent_id,
|
||||
status="queued",
|
||||
created_at=execution_data["created_at"]
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to start agent execution: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to start agent execution")
|
||||
|
||||
|
||||
@router.get("/executions/{execution_id}", response_model=AgentExecutionStatus)
|
||||
async def get_execution_status(
|
||||
execution_id: str = Path(..., description="Execution identifier"),
|
||||
token: CapabilityToken = Depends(verify_capability)
|
||||
) -> AgentExecutionStatus:
|
||||
"""Get agent execution status"""
|
||||
|
||||
if execution_id not in _active_executions:
|
||||
raise HTTPException(status_code=404, detail="Execution not found")
|
||||
|
||||
execution = _active_executions[execution_id]
|
||||
|
||||
return AgentExecutionStatus(
|
||||
execution_id=execution_id,
|
||||
agent_id=execution["agent_id"],
|
||||
status=execution["status"],
|
||||
progress=execution.get("progress"),
|
||||
result=execution.get("result"),
|
||||
error=execution.get("error"),
|
||||
created_at=execution["created_at"],
|
||||
updated_at=execution["updated_at"],
|
||||
completed_at=execution.get("completed_at")
|
||||
)
|
||||
|
||||
|
||||
async def _execute_agent_async(execution_id: str, agent_id: str, request: AgentExecutionRequest, token: CapabilityToken):
|
||||
"""Execute agent asynchronously"""
|
||||
try:
|
||||
# Update status to running
|
||||
_active_executions[execution_id].update({
|
||||
"status": "running",
|
||||
"updated_at": datetime.utcnow(),
|
||||
"progress": 0.0
|
||||
})
|
||||
|
||||
# Simulate agent execution - replace with real agent orchestrator
|
||||
await asyncio.sleep(0.5) # Initial setup
|
||||
_active_executions[execution_id]["progress"] = 25.0
|
||||
|
||||
await asyncio.sleep(1.0) # Processing
|
||||
_active_executions[execution_id]["progress"] = 50.0
|
||||
|
||||
await asyncio.sleep(1.0) # Generating result
|
||||
_active_executions[execution_id]["progress"] = 75.0
|
||||
|
||||
# Simulate successful completion
|
||||
result = {
|
||||
"agent_id": agent_id,
|
||||
"output": f"Agent {agent_id} completed successfully",
|
||||
"processed_data": request.input_data,
|
||||
"execution_time_seconds": 2.5,
|
||||
"tokens_used": 150,
|
||||
"cost": 0.002
|
||||
}
|
||||
|
||||
# Update to completed
|
||||
_active_executions[execution_id].update({
|
||||
"status": "completed",
|
||||
"progress": 100.0,
|
||||
"result": result,
|
||||
"updated_at": datetime.utcnow(),
|
||||
"completed_at": datetime.utcnow()
|
||||
})
|
||||
|
||||
logger.info(f"Agent execution {execution_id} completed successfully")
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
_active_executions[execution_id].update({
|
||||
"status": "timeout",
|
||||
"error": "Execution timeout",
|
||||
"updated_at": datetime.utcnow(),
|
||||
"completed_at": datetime.utcnow()
|
||||
})
|
||||
logger.error(f"Agent execution {execution_id} timed out")
|
||||
|
||||
except Exception as e:
|
||||
_active_executions[execution_id].update({
|
||||
"status": "failed",
|
||||
"error": str(e),
|
||||
"updated_at": datetime.utcnow(),
|
||||
"completed_at": datetime.utcnow()
|
||||
})
|
||||
logger.error(f"Agent execution {execution_id} failed: {e}")
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def list_available_agents(
|
||||
token: CapabilityToken = Depends(verify_capability)
|
||||
) -> Dict[str, Any]:
|
||||
"""List available agents for execution"""
|
||||
|
||||
# Return available agents - replace with real agent registry
|
||||
available_agents = {
|
||||
"coding_assistant": {
|
||||
"id": "coding_assistant",
|
||||
"name": "Coding Agent",
|
||||
"description": "AI agent specialized in code generation and review",
|
||||
"capabilities": ["code_generation", "code_review", "debugging"],
|
||||
"status": "available"
|
||||
},
|
||||
"research_agent": {
|
||||
"id": "research_agent",
|
||||
"name": "Research Agent",
|
||||
"description": "AI agent for information gathering and analysis",
|
||||
"capabilities": ["web_search", "document_analysis", "summarization"],
|
||||
"status": "available"
|
||||
},
|
||||
"data_analyst": {
|
||||
"id": "data_analyst",
|
||||
"name": "Data Analyst",
|
||||
"description": "AI agent for data analysis and visualization",
|
||||
"capabilities": ["data_processing", "visualization", "statistical_analysis"],
|
||||
"status": "available"
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"agents": available_agents,
|
||||
"total_count": len(available_agents),
|
||||
"available_count": len([a for a in available_agents.values() if a["status"] == "available"])
|
||||
}
|
||||
Reference in New Issue
Block a user