Skip to main content
Glama
agents.py9.7 kB
""" Critique agents and synthesis logic using instructor and Google AI. This module implements the core thinking augmentation system with specialized agents for different critique perspectives and a synthesis agent that combines all perspectives into a coherent analysis. """ import asyncio import logging from datetime import UTC, datetime from pydantic import ValidationError from .client import get_critique_client, get_synthesis_client from .models import ( CritiquePerspective, CritiqueRequest, CritiqueResponse, SynthesisResponse, ThinkingAugmentationResult, ) logger = logging.getLogger(__name__) class CritiqueAgent: """Base class for critique agents with different perspectives.""" def __init__( self, perspective: CritiquePerspective, model_name: str = "gemini-2.5-flash", ): self.perspective = perspective self.model_name = model_name # Get instructor client with Google AI self.client = get_critique_client(model_name) def _get_system_prompt(self) -> str: """Get the system prompt for this critique perspective.""" base_prompt = f"""You are an expert analyst tasked with providing a {self.perspective} critique of proposals. Your role is to thoroughly analyze the proposal from a {self.perspective} perspective, focusing on: - Providing balanced, evidence-based analysis - Identifying key strengths, weaknesses, or neutral observations - Considering multiple stakeholders and scenarios - Being specific and actionable in your insights You must provide structured analysis covering feasibility, risks, benefits, implementation, stakeholder impact, and resource requirements. Your confidence level should reflect the certainty of your analysis based on the information provided.""" perspective_specific = { "positive": """ Focus on: - Strengths and advantages of the proposal - Potential for positive outcomes and success - Opportunities and benefits for stakeholders - Ways the proposal could exceed expectations - Innovative or particularly strong aspects While maintaining objectivity, emphasize the constructive and optimistic aspects of the analysis.""", "negative": """ Focus on: - Potential weaknesses and vulnerabilities - Risks, challenges, and obstacles - Unintended consequences and downsides - Resource constraints and limitations - Areas where the proposal might fall short While being constructively critical, identify genuine concerns and potential failure modes.""", "neutral": """ Focus on: - Objective, balanced assessment - Trade-offs and competing considerations - Factual analysis without bias toward success or failure - Realistic expectations and likely outcomes - Areas requiring more information or clarification Provide an impartial, evidence-based perspective that considers both positives and negatives.""", } return base_prompt + "\n\n" + perspective_specific[self.perspective] async def analyze_proposal(self, proposal: str) -> CritiqueResponse: """Analyze a proposal from this agent's perspective.""" try: system_prompt = self._get_system_prompt() user_prompt = f"Please analyze the following proposal:\n\n{proposal}" # Use instructor to get structured response response = await self.client.chat.completions.create( response_model=CritiqueResponse, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], generation_config={ "temperature": 0.7, "max_tokens": 2000, }, ) return response except ValidationError as e: logger.error(f"Validation error in {self.perspective} critique: {e}") raise except Exception as e: logger.error(f"Error in {self.perspective} critique: {e}") raise class SynthesisAgent: """Agent responsible for synthesizing multiple critiques into a coherent analysis.""" def __init__(self, model_name: str = "gemini-2.5-pro"): self.model_name = model_name # Get instructor client with Google AI self.client = get_synthesis_client(model_name) def _get_system_prompt(self) -> str: """Get the system prompt for synthesis.""" return """You are an expert synthesis analyst responsible for combining multiple critique perspectives into a coherent, actionable analysis. Your role is to: - Identify areas of consensus and disagreement among the critiques - Synthesize insights from positive, neutral, and negative perspectives - Provide a balanced, evidence-based recommendation - Highlight critical considerations and next steps - Flag areas of significant uncertainty You should: - Weight insights based on their validity and supporting evidence - Acknowledge trade-offs and competing priorities - Provide actionable recommendations and next steps - Be honest about limitations and uncertainties - Focus on practical outcomes and decision-making Your synthesis should help decision-makers understand the full picture and make informed choices.""" async def synthesize_critiques( self, original_proposal: str, critiques: list[CritiqueResponse] ) -> SynthesisResponse: """Synthesize multiple critiques into a comprehensive analysis.""" try: system_prompt = self._get_system_prompt() # Build critiques section critiques_text = "" for critique in critiques: key_insights_text = ", ".join(critique.key_insights) critiques_text += f""" **{critique.perspective.title()} Perspective:** Executive Summary: {critique.executive_summary} Analysis: - Feasibility: {critique.analysis.feasibility} - Risks: {critique.analysis.risks} - Benefits: {critique.analysis.benefits} - Implementation: {critique.analysis.implementation} - Stakeholder Impact: {critique.analysis.stakeholder_impact} - Resource Requirements: {critique.analysis.resource_requirements} Key Insights: {key_insights_text} Confidence: {critique.confidence_level} """ user_prompt = f""" Please synthesize the following critiques of this proposal: **Original Proposal:** {original_proposal} **Critiques:** {critiques_text} Provide a comprehensive synthesis that identifies consensus, disagreements, and actionable recommendations. """ # Use instructor to get structured response response = await self.client.chat.completions.create( response_model=SynthesisResponse, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt}, ], generation_config={ # Lower temperature for more consistent synthesis "temperature": 0.3, "max_tokens": 3000, }, ) return response except ValidationError as e: logger.error(f"Validation error in synthesis: {e}") raise except Exception as e: logger.error(f"Error in synthesis: {e}") raise async def process_proposal(request: CritiqueRequest) -> ThinkingAugmentationResult: """Process a proposal through the complete thinking augmentation pipeline.""" start_time = datetime.now(UTC) try: logger.info("Starting thinking augmentation process") # Create agents for this processing request positive_agent = CritiqueAgent("positive") neutral_agent = CritiqueAgent("neutral") negative_agent = CritiqueAgent("negative") synthesis_agent = SynthesisAgent() # Run all critiques in parallel critique_tasks = [ positive_agent.analyze_proposal(request.proposal), neutral_agent.analyze_proposal(request.proposal), negative_agent.analyze_proposal(request.proposal), ] logger.info("Running parallel critiques") critiques = await asyncio.gather(*critique_tasks) logger.info("Critiques completed, starting synthesis") # Synthesize all critiques synthesis = await synthesis_agent.synthesize_critiques( request.proposal, critiques ) end_time = datetime.now(UTC) processing_time = (end_time - start_time).total_seconds() logger.info(f"Thinking augmentation completed in {processing_time:.2f} seconds") # Create final result result = ThinkingAugmentationResult( original_proposal=request.proposal, critiques=critiques, synthesis=synthesis, processing_metadata={ "start_time": start_time.isoformat(), "end_time": end_time.isoformat(), "processing_time_seconds": processing_time, "critique_model": "gemini-2.5-flash", "synthesis_model": "gemini-2.5-pro", "num_critiques": len(critiques), }, ) return result except Exception as e: logger.error(f"Error in thinking augmentation process: {e}") raise # Convenience function for easy access async def consult_the_council(proposal: str) -> ThinkingAugmentationResult: """Convenience function to consult the council for thinking augmentation.""" request = CritiqueRequest(proposal=proposal) return await process_proposal(request)

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dogonthehorizon/elrond-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server