debatearena / server /tasks.py
Shivappa Sangapur
feat: DebateArenaEnv complete - server/client separation, LLM multi-agent, Docker, OpenEnv compliant
b1eddd6
Raw History Blame Contribute Delete
7.69 kB
"""
DebateArenaEnv — Topic bank and adaptive curriculum.
TopicRegistry tracks per-topic win-rates and escalates difficulty
when the agent wins >= 70% of episodes over the last >= 3 attempts.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional
# ──────────────────────────────────────────────────────────────────────────────
# Topic dataclass
# ──────────────────────────────────────────────────────────────────────────────
@dataclass
class Topic:
topic_id: str
difficulty: str # "easy" | "medium" | "hard"
domain: str
claim: str
narrative: str
known_facts: Dict[str, bool] # fact_key → True/False
known_fallacies: List[str]
evidence_keywords: List[str]
max_rounds: int = 5
self_play_seed: int = 42
def to_prompt(self) -> str:
return (
f"Motion: {self.claim}\n"
f"Domain: {self.domain}\n"
f"Background: {self.narrative}\n"
f"Max rounds: {self.max_rounds}"
)
def to_dict(self) -> Dict[str, Any]:
return {
"topic_id": self.topic_id,
"difficulty": self.difficulty,
"domain": self.domain,
"claim": self.claim,
"narrative": self.narrative,
"known_facts": self.known_facts,
"known_fallacies": self.known_fallacies,
"evidence_keywords": self.evidence_keywords,
"max_rounds": self.max_rounds,
}
# ──────────────────────────────────────────────────────────────────────────────
# Topic bank (3 topics: easy / medium / hard)
# ──────────────────────────────────────────────────────────────────────────────
TOPIC_BANK: List[Topic] = [
Topic(
topic_id="easy",
difficulty="easy",
domain="AI Policy & Media",
claim="Social media platforms should be legally required to label AI-generated content.",
narrative=(
"Deepfakes and synthetic media are increasingly used in disinformation campaigns. "
"The EU AI Act mandates labelling; the US DEFIANCE Act is under debate. "
"Proponents argue transparency protects democratic discourse."
),
known_facts={
"EU_AI_Act_mandates_labelling": True,
"deepfakes_used_in_elections_2024": True,
"labelling_eliminates_disinformation": False,
"US_DEFIANCE_Act_passed": False,
},
known_fallacies=["slippery_slope", "appeal_to_fear"],
evidence_keywords=[
"EU AI Act", "DEFIANCE Act", "synthetic media",
"disinformation", "transparency", "deepfake",
],
max_rounds=5,
),
Topic(
topic_id="medium",
difficulty="medium",
domain="Climate & Energy Policy",
claim="Governments should mandate a complete phase-out of fossil fuels by 2035.",
narrative=(
"IPCC reports warn that net-zero by 2050 requires rapid decarbonisation. "
"Several EU nations have set 2035 targets; critics cite energy security risks. "
"Renewables now account for 30% of global electricity."
),
known_facts={
"IPCC_net_zero_2050_target": True,
"renewables_30pct_global_electricity": True,
"fossil_fuel_phaseout_causes_blackouts": False,
"EU_2035_fossil_fuel_ban_enacted": False,
},
known_fallacies=["false_dilemma", "appeal_to_nature"],
evidence_keywords=[
"IPCC", "net-zero", "decarbonisation", "renewables",
"energy security", "carbon emissions",
],
max_rounds=6,
),
Topic(
topic_id="hard",
difficulty="hard",
domain="Bioethics & Genomics",
claim="Human germline gene editing for disease prevention should be legally permitted.",
narrative=(
"CRISPR-Cas9 enables heritable edits. The He Jiankui case triggered global bans. "
"Proponents cite eradication of hereditary diseases; opponents warn of eugenics slippery slopes. "
"WHO guidelines call for a moratorium pending governance frameworks."
),
known_facts={
"CRISPR_enables_heritable_edits": True,
"WHO_moratorium_on_germline_editing": True,
"germline_editing_eradicates_all_disease": False,
"He_Jiankui_case_led_to_global_ban": False, # led to bans in many, not all countries
},
known_fallacies=["slippery_slope", "appeal_to_nature", "false_dilemma"],
evidence_keywords=[
"CRISPR", "germline", "WHO", "hereditary disease",
"bioethics", "eugenics", "governance",
],
max_rounds=7,
),
]
# Lookup by topic_id
_TOPIC_MAP: Dict[str, Topic] = {t.topic_id: t for t in TOPIC_BANK}
# ──────────────────────────────────────────────────────────────────────────────
# Adaptive curriculum
# ──────────────────────────────────────────────────────────────────────────────
@dataclass
class TopicRegistry:
"""
Tracks per-topic win-rates and escalates difficulty.
Escalation rule:
win_rate >= 0.70 over the last >= 3 attempts → bump to next difficulty
"""
_history: Dict[str, List[bool]] = field(default_factory=dict)
def get_topic(self, topic_id: str) -> Optional[Topic]:
return _TOPIC_MAP.get(topic_id)
def current_topic(self) -> Topic:
"""Return the easiest topic that hasn't been mastered yet."""
order = ["easy", "medium", "hard"]
for tid in order:
if not self._is_mastered(tid):
return _TOPIC_MAP[tid]
return _TOPIC_MAP["hard"]
def update_curriculum(self, topic_id: str, won: bool) -> None:
self._history.setdefault(topic_id, []).append(won)
def win_rate(self, topic_id: str) -> float:
hist = self._history.get(topic_id, [])
if not hist:
return 0.0
return sum(hist) / len(hist)
def attempts(self, topic_id: str) -> int:
return len(self._history.get(topic_id, []))
def _is_mastered(self, topic_id: str) -> bool:
return self.attempts(topic_id) >= 3 and self.win_rate(topic_id) >= 0.70
def summary(self) -> Dict[str, Any]:
return {
tid: {
"attempts": self.attempts(tid),
"win_rate": round(self.win_rate(tid), 3),
"mastered": self._is_mastered(tid),
}
for tid in _TOPIC_MAP
}
# Singleton used by the environment
REGISTRY = TopicRegistry()