refactored: to utilise the google adk and production grade agent
Some checks failed
validation / verify (push) Failing after 10s
Some checks failed
validation / verify (push) Failing after 10s
This commit is contained in:
196
app/adk/agents.py
Normal file
196
app/adk/agents.py
Normal file
@@ -0,0 +1,196 @@
|
||||
"""ADK Multi-Agent Architecture for GCP Solution Architecture Agent.
|
||||
|
||||
Uses google.adk.agents primitives:
|
||||
- SourceDiscoveryAgent (LlmAgent)
|
||||
- DiscoveryAgent (LlmAgent)
|
||||
- ArchitectureDesignAgent (LlmAgent)
|
||||
- ValidationReviewAgent (LlmAgent)
|
||||
- PackagingAgent (LlmAgent)
|
||||
- OrchestratorLoopAgent (LoopAgent)
|
||||
"""
|
||||
|
||||
import logging
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from app.adk.compat import BaseAgent, LlmAgent, LoopAgent, SequentialAgent
|
||||
from app.adk.tools import ADK_TOOLS
|
||||
from app.config import get_settings
|
||||
from app.database import get_db_manager
|
||||
from app.nodes import design_node, discover_node, package_node, source_discover_node, validate_node
|
||||
from app.skills.loader import SkillLoader
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SourceDiscoveryAgent(LlmAgent):
|
||||
"""ADK Agent responsible for Phase 0a Pre-emptive Source Environment Discovery."""
|
||||
|
||||
def __init__(self, skill_loader: SkillLoader) -> None:
|
||||
super().__init__(
|
||||
name="SourceDiscoveryAgent",
|
||||
description="Audits and documents the pre-existing source environment (As-Is Architecture) before target migration.",
|
||||
instruction=skill_loader.format_skills_for_prompt("source_discover"),
|
||||
tools=[],
|
||||
)
|
||||
self.skill_loader = skill_loader
|
||||
|
||||
def execute(self, state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
logger.info("Executing SourceDiscoveryAgent")
|
||||
res = source_discover_node(state, self.skill_loader)
|
||||
state_copy = dict(state)
|
||||
state_copy.update(res)
|
||||
return state_copy
|
||||
|
||||
|
||||
class DiscoveryAgent(LlmAgent):
|
||||
"""ADK Agent responsible for Phase 0 Requirements Discovery."""
|
||||
|
||||
def __init__(self, skill_loader: SkillLoader) -> None:
|
||||
super().__init__(
|
||||
name="DiscoveryAgent",
|
||||
description="Extracts functional and non-functional requirements with product selection deferred.",
|
||||
instruction=skill_loader.format_skills_for_prompt("discover"),
|
||||
tools=[],
|
||||
)
|
||||
self.skill_loader = skill_loader
|
||||
|
||||
def execute(self, state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
logger.info("Executing DiscoveryAgent")
|
||||
res = discover_node(state, self.skill_loader)
|
||||
state_copy = dict(state)
|
||||
state_copy.update(res)
|
||||
return state_copy
|
||||
|
||||
|
||||
class ArchitectureDesignAgent(LlmAgent):
|
||||
"""ADK Agent responsible for Phase 1 Product Selection, Diagrams, & Terraform IaC."""
|
||||
|
||||
def __init__(self, skill_loader: SkillLoader) -> None:
|
||||
super().__init__(
|
||||
name="ArchitectureDesignAgent",
|
||||
description="Selects GCP products, generates Mermaid diagram, and produces Terraform IaC grounded by Developer Knowledge MCP.",
|
||||
instruction=skill_loader.format_skills_for_prompt("design"),
|
||||
tools=ADK_TOOLS,
|
||||
)
|
||||
self.skill_loader = skill_loader
|
||||
|
||||
def execute(self, state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
logger.info("Executing ArchitectureDesignAgent")
|
||||
res = design_node(state, self.skill_loader)
|
||||
state_copy = dict(state)
|
||||
state_copy.update(res)
|
||||
return state_copy
|
||||
|
||||
|
||||
class ValidationReviewAgent(LlmAgent):
|
||||
"""ADK Agent responsible for Phase 2 Artifact Review & Quality Validation."""
|
||||
|
||||
def __init__(self, skill_loader: SkillLoader) -> None:
|
||||
super().__init__(
|
||||
name="ValidationReviewAgent",
|
||||
description="Validates Mermaid syntax, Terraform configuration, and required sections.",
|
||||
instruction=skill_loader.format_skills_for_prompt("validate"),
|
||||
tools=ADK_TOOLS,
|
||||
)
|
||||
self.skill_loader = skill_loader
|
||||
|
||||
def execute(self, state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
logger.info("Executing ValidationReviewAgent")
|
||||
res = validate_node(state, self.skill_loader)
|
||||
state_copy = dict(state)
|
||||
state_copy.update(res)
|
||||
return state_copy
|
||||
|
||||
|
||||
class PackagingAgent(LlmAgent):
|
||||
"""ADK Agent responsible for Phase 3 Solution Guide Packaging."""
|
||||
|
||||
def __init__(self, skill_loader: SkillLoader) -> None:
|
||||
super().__init__(
|
||||
name="PackagingAgent",
|
||||
description="Packages final solution-architecture-guide.md.",
|
||||
instruction=skill_loader.format_skills_for_prompt("package"),
|
||||
tools=[],
|
||||
)
|
||||
self.skill_loader = skill_loader
|
||||
|
||||
def execute(self, state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
logger.info("Executing PackagingAgent")
|
||||
res = package_node(state, self.skill_loader)
|
||||
state_copy = dict(state)
|
||||
state_copy.update(res)
|
||||
return state_copy
|
||||
|
||||
|
||||
class OrchestratorLoopAgent(LoopAgent):
|
||||
"""ADK Orchestrator LoopAgent that coordinates multi-agent execution & iterative quality review.
|
||||
|
||||
Uses google.adk.agents.LoopAgent to execute discovery -> design -> validation review -> packaging
|
||||
in a loop until validation passes 100% or max_iterations is reached. Writes every review iteration
|
||||
event to PostgreSQL database (`orchestrator_review_logs`).
|
||||
"""
|
||||
|
||||
def __init__(self, skill_loader: SkillLoader, max_iterations: Optional[int] = None) -> None:
|
||||
settings = get_settings()
|
||||
max_iters = max_iterations or settings.ADK_MAX_LOOP_ITERATIONS
|
||||
self.db_manager = get_db_manager()
|
||||
|
||||
self.source_discovery_agent = SourceDiscoveryAgent(skill_loader)
|
||||
self.discovery_agent = DiscoveryAgent(skill_loader)
|
||||
self.design_agent = ArchitectureDesignAgent(skill_loader)
|
||||
self.validation_agent = ValidationReviewAgent(skill_loader)
|
||||
self.packaging_agent = PackagingAgent(skill_loader)
|
||||
|
||||
sub_pipeline = SequentialAgent(
|
||||
name="MultiAgentGCPPipeline",
|
||||
sub_agents=[
|
||||
self.source_discovery_agent,
|
||||
self.discovery_agent,
|
||||
self.design_agent,
|
||||
self.validation_agent,
|
||||
self.packaging_agent,
|
||||
],
|
||||
description="Sequential pipeline of GCP architecture multi-agents.",
|
||||
)
|
||||
|
||||
def review_validator(state: Dict[str, Any]) -> bool:
|
||||
"""Check if solution meets production quality validation standards."""
|
||||
is_valid = state.get("validation_passed", False)
|
||||
errors = state.get("errors", [])
|
||||
iteration = state.get("loop_count", 1)
|
||||
execution_id = state.get("execution_id", str(uuid.uuid4()))
|
||||
|
||||
status_str = "APPROVED" if is_valid else "NEEDS_REVISION"
|
||||
feedback_str = "All architecture validation rules passed." if is_valid else f"Validation errors: {', '.join(errors)}"
|
||||
|
||||
# Record review iteration in PostgreSQL database
|
||||
self.db_manager.record_orchestrator_log(
|
||||
log_id=str(uuid.uuid4()),
|
||||
execution_id=execution_id,
|
||||
iteration=iteration,
|
||||
review_status=status_str,
|
||||
reviewer_agent="ValidationReviewAgent",
|
||||
feedback=feedback_str,
|
||||
)
|
||||
logger.info(
|
||||
"Orchestrator Review Loop #%d: status=%s, valid=%s",
|
||||
iteration,
|
||||
status_str,
|
||||
is_valid,
|
||||
)
|
||||
|
||||
return is_valid
|
||||
|
||||
super().__init__(
|
||||
name="OrchestratorLoopAgent",
|
||||
sub_agent=sub_pipeline,
|
||||
max_iterations=max_iters,
|
||||
description="Production-ready multi-agent orchestrator loop agent.",
|
||||
validator_fn=review_validator,
|
||||
)
|
||||
|
||||
|
||||
def build_adk_multi_agent_system(skill_loader: SkillLoader, max_iterations: Optional[int] = None) -> OrchestratorLoopAgent:
|
||||
"""Factory function for building the complete ADK Orchestrator LoopAgent system."""
|
||||
return OrchestratorLoopAgent(skill_loader, max_iterations=max_iterations)
|
||||
Reference in New Issue
Block a user