| """Query Complexity Classifier
|
|
|
| Determines whether a query needs full debate or can be answered directly.
|
|
|
| This prevents over-activation: simple factual questions get direct answers,
|
| while complex/ambiguous questions trigger full multi-agent reasoning.
|
| """
|
|
|
| import re
|
| from enum import Enum
|
|
|
|
|
| class QueryComplexity(Enum):
|
| """Query complexity levels"""
|
| SIMPLE = "simple"
|
| MEDIUM = "medium"
|
| COMPLEX = "complex"
|
|
|
|
|
| class QueryClassifier:
|
| """Classify query complexity to determine reasoning depth."""
|
|
|
|
|
| FACTUAL_PATTERNS = [
|
| r"what is the (speed|velocity|mass|temperature|distance|height|width|size|weight|color|pressure|density|definition|meaning|name)",
|
| r"define ",
|
| r"what (year|date|time) ",
|
| r"how fast (is|can)",
|
| r"how high is",
|
| r"how long is",
|
| r"what (color|size|shape)",
|
| r"who (is|wrote|created|invented|discovered|founded)",
|
| r"where (is|are)",
|
| r"what is the (capital|president|king|queen|currency|language|population)",
|
| r"list of ",
|
| r"formula for",
|
| r"calculate ",
|
| ]
|
|
|
|
|
| AMBIGUOUS_PATTERNS = [
|
| r"could .* really",
|
| r"might .* ever",
|
| r"can .* (truly|really)",
|
| r"what does .* (really )?mean",
|
| r"why (do|does) (we|they|people)",
|
| r"is .* the (future|destiny|past|foundation|basis|purpose)",
|
| r"can .* (be|become|achieve)",
|
| ]
|
|
|
|
|
| ETHICS_PATTERNS = [
|
| r"should (we |i |ai|society|companies)",
|
| r"is it (right|wrong|ethical|moral)",
|
| r"is it (good|bad|fair)",
|
| r"ought",
|
| r"morally?",
|
| r"ethics?",
|
| r"value of",
|
| r"meaning of",
|
| r"purpose of",
|
| r"how should (we |ai|companies|society)",
|
| r"balance .* (freedom|individual|collective|good|rights)",
|
| ]
|
|
|
|
|
|
|
|
|
| MULTIDOMAIN_PATTERNS = [
|
| r"relationship .*(consciousness|meaning|identity|knowledge|reality)",
|
| r"interaction .*(human|society|culture|mind|consciousness)",
|
| r"(challenge|question) .* (understanding|reality|belief|knowledge)",
|
| ]
|
|
|
|
|
| SUBJECTIVE_PATTERNS = [
|
| r"is .*consciousness",
|
| r"do you (think|believe)",
|
| r"perspective",
|
| r"what is (the )?nature of",
|
| r"can .* (be|become) (measured|quantified|understood)",
|
| ]
|
|
|
| def classify(self, query: str) -> QueryComplexity:
|
| """Classify query complexity.
|
|
|
| Args:
|
| query: The user query
|
|
|
| Returns:
|
| QueryComplexity level (SIMPLE, MEDIUM, or COMPLEX)
|
| """
|
| query_lower = query.lower().strip()
|
|
|
|
|
| if self._is_factual(query_lower):
|
|
|
| if self._has_ambiguity(query_lower) or self._has_ethics(query_lower):
|
| return QueryComplexity.COMPLEX
|
| return QueryComplexity.SIMPLE
|
|
|
|
|
| if self._has_ethics(query_lower):
|
| return QueryComplexity.COMPLEX
|
| if self._has_ambiguity(query_lower):
|
| return QueryComplexity.COMPLEX
|
| if self._has_multidomain(query_lower):
|
| return QueryComplexity.COMPLEX
|
| if self._has_subjective(query_lower):
|
| return QueryComplexity.COMPLEX
|
|
|
|
|
| return QueryComplexity.MEDIUM
|
|
|
| def _is_factual(self, query: str) -> bool:
|
| """Check if query is direct factual question."""
|
| return any(re.search(pattern, query) for pattern in self.FACTUAL_PATTERNS)
|
|
|
| def _has_ambiguity(self, query: str) -> bool:
|
| """Check if query has ambiguity markers."""
|
| return any(re.search(pattern, query) for pattern in self.AMBIGUOUS_PATTERNS)
|
|
|
| def _has_ethics(self, query: str) -> bool:
|
| """Check if query involves ethics/philosophy."""
|
| return any(re.search(pattern, query) for pattern in self.ETHICS_PATTERNS)
|
|
|
| def _has_multidomain(self, query: str) -> bool:
|
| """Check if query spans multiple domains."""
|
| return any(re.search(pattern, query) for pattern in self.MULTIDOMAIN_PATTERNS)
|
|
|
| def _has_subjective(self, query: str) -> bool:
|
| """Check if query invites subjective reasoning."""
|
| return any(re.search(pattern, query) for pattern in self.SUBJECTIVE_PATTERNS)
|
|
|
| def select_agents(
|
| self, complexity: QueryComplexity, domain: str
|
| ) -> dict[str, float]:
|
| """Select agents and their weights based on complexity and domain.
|
|
|
| Args:
|
| complexity: Query complexity level
|
| domain: Detected query domain
|
|
|
| Returns:
|
| Dict mapping agent names to activation weights (0-1)
|
| """
|
|
|
| all_agents = {
|
| "Newton": ["physics", "mathematics", "systems"],
|
| "Quantum": ["physics", "uncertainty", "systems"],
|
| "Philosophy": ["philosophy", "meaning", "consciousness"],
|
| "DaVinci": ["creativity", "systems", "innovation"],
|
| "Empathy": ["ethics", "consciousness", "meaning"],
|
| "Ethics": ["ethics", "consciousness", "meaning"],
|
| }
|
|
|
| domain_agents = all_agents
|
|
|
| if complexity == QueryComplexity.SIMPLE:
|
|
|
|
|
| primary = self._get_primary_agent(domain)
|
| return {primary: 1.0}
|
|
|
| elif complexity == QueryComplexity.MEDIUM:
|
|
|
|
|
| primary = self._get_primary_agent(domain)
|
| secondaries = self._get_secondary_agents(domain, count=1)
|
|
|
| weights = {primary: 1.0}
|
| for secondary in secondaries:
|
| weights[secondary] = 0.6
|
|
|
| return weights
|
|
|
| else:
|
|
|
|
|
| primary = self._get_primary_agent(domain)
|
| secondaries = self._get_secondary_agents(domain, count=2)
|
| cross_domain = self._get_cross_domain_agents(domain, count=1)
|
|
|
| weights = {primary: 1.0}
|
| for secondary in secondaries:
|
| weights[secondary] = 0.7
|
| for cross in cross_domain:
|
| weights[cross] = 0.4
|
|
|
| return weights
|
|
|
| def _get_primary_agent(self, domain: str) -> str:
|
| """Get the primary agent for a domain."""
|
| domain_map = {
|
| "physics": "Newton",
|
| "mathematics": "Newton",
|
| "creativity": "DaVinci",
|
| "ethics": "Ethics",
|
| "philosophy": "Philosophy",
|
| "meaning": "Philosophy",
|
| "consciousness": "Empathy",
|
| "uncertainty": "Quantum",
|
| "systems": "Newton",
|
| }
|
| return domain_map.get(domain, "Newton")
|
|
|
| def _get_secondary_agents(self, domain: str, count: int = 1) -> list[str]:
|
| """Get secondary agents for a domain."""
|
| domain_map = {
|
| "physics": ["Quantum", "DaVinci"],
|
| "mathematics": ["Quantum", "Philosophy"],
|
| "creativity": ["Quantum", "Empathy"],
|
| "ethics": ["Philosophy", "Empathy"],
|
| "philosophy": ["Empathy", "Ethics"],
|
| "meaning": ["Quantum", "DaVinci"],
|
| "consciousness": ["Philosophy", "Quantum"],
|
| "uncertainty": ["Philosophy", "DaVinci"],
|
| "systems": ["DaVinci", "Philosophy"],
|
| }
|
| candidates = domain_map.get(domain, ["Philosophy", "DaVinci"])
|
| return candidates[:count]
|
|
|
| def _get_cross_domain_agents(self, domain: str, count: int = 1) -> list[str]:
|
| """Get cross-domain agents (useful for all domains)."""
|
|
|
| candidates = ["Philosophy", "Empathy", "DaVinci"]
|
| return candidates[:count]
|
|
|