# ============================================================================ # openenv.yaml v1.1.0 # OpenEnv environment specification — passes `openenv validate` # ============================================================================ name: information-integrity-env version: "1.1.0" author: openenv-content-moderation description: > A deterministic, benchmarkable content moderation environment where agents verify claims, reason over pre-built evidence sources, and make explainable moderation decisions (allow / flag / remove). Evaluation runs fully offline — no external API calls during episodes. Three difficulty tiers (easy / medium / hard) with static scenario datasets ensure reproducible, comparable benchmarks across agent runs. license: Apache-2.0 # --------------------------------------------------------------------------- # Server # --------------------------------------------------------------------------- server: type: http reset_endpoint: POST /reset step_endpoint: POST /step health_endpoint: GET /health tasks_endpoint: GET /tasks grade_endpoint: POST /grade collect_endpoint: POST /collect # dataset creation only; not used during eval state_endpoint: GET /state/{session_id} # --------------------------------------------------------------------------- # Observation space # --------------------------------------------------------------------------- observation: type: object description: > The agent observes the content under review, extracted claims (with live verification status), a pre-built evidence pool, and a running interaction history. Ground truth is never exposed. properties: content: type: string description: The piece of content under moderation review. claims: type: array description: Verifiable claims extracted from the content. items: type: object properties: id: { type: string } text: { type: string } verification_status: { type: string, enum: [unverified, true, false, partially_true, unknown] } confidence: { type: number, minimum: 0.0, maximum: 1.0 } verified_by_sources: { type: array, items: { type: string } } available_sources: type: array description: Pre-built evidence pool — fully deterministic, no live fetching. items: type: object properties: id: { type: string } title: { type: string } text: { type: string } url: { type: string } stance: { type: string, enum: [supporting, contradicting, neutral] } reliability: { type: number, minimum: 0.0, maximum: 1.0 } source_type: { type: string } interaction_history: type: array description: Log of all previous actions and their results this episode. status_flags: type: object properties: decision_made: { type: boolean } sufficient_evidence: { type: boolean } premature_decision: { type: boolean } redundant_actions: { type: integer } max_steps_reached: { type: boolean } step_count: { type: integer } episode_id: { type: string } task_difficulty: { type: string, enum: [easy, medium, hard] } # --------------------------------------------------------------------------- # Action space # --------------------------------------------------------------------------- actions: verify_claim: description: Investigate a specific claim and receive its verification status. required_fields: [claim_id] optional_fields: [reasoning] example: type: verify_claim claim_id: claim_001 reasoning: "This is the central assertion — verify first." check_source: description: Read a source and receive its full text, stance, and reliability. required_fields: [source_id] optional_fields: [reasoning] example: type: check_source source_id: src_003 reasoning: "WHO source — likely authoritative." decide: description: > Make the final moderation decision, ending the episode. Must verify >= 1 claim and check >= 2 sources first (or incur premature penalty). required_fields: [decision] optional_fields: [reasoning] example: type: decide decision: remove reasoning: "All claims false per three high-reliability sources." # --------------------------------------------------------------------------- # Reward # --------------------------------------------------------------------------- reward: type: float range: [-2.0, 2.0] description: > Dense step-level reward. Non-sparse by design — agents receive positive signals for every unique claim verified and source checked. See reward_config.yaml for configurable magnitudes. components: verify_claim_reward: "+0.20 per unique claim verified" check_source_reward: "+0.20 per unique source checked" multi_source_bonus: "+0.20 when >= 3 unique sources checked" decision_correct: "+1.00 exact match with ground truth" decision_partial: "+0.50 one step away (flag<->remove, flag<->allow)" decision_wrong: "0.00" premature_decision: "-0.50 deciding before sufficient evidence" redundant_action: "-0.10 re-verifying / re-checking same id" step_inefficiency: "-0.05 per step beyond efficient threshold" over_aggression: "-0.30 choosing remove when ground truth is allow/flag" # --------------------------------------------------------------------------- # Tasks (deterministic datasets — no live API calls) # --------------------------------------------------------------------------- tasks: - name: easy grader: tasks.easy.grader.grade_episode - name: medium grader: tasks.medium.grader.grade_episode - name: hard grader: tasks.hard.grader.grade_episode # --------------------------------------------------------------------------- # Grader # --------------------------------------------------------------------------- grader: output_range: [0.0, 1.0] dimensions: decision_score: description: Correctness of the final moderation call (partial credit for adjacent decisions) evidence_score: description: Fraction of available sources consulted reasoning_score: description: Fraction of claims fully verified before deciding efficiency_score: description: Steps used relative to difficulty-specific ideal maximum # --------------------------------------------------------------------------- # Evaluation protocol # --------------------------------------------------------------------------- evaluation: description: > Run inference.py in benchmark mode to evaluate an agent across all 15 scenarios. No external API calls are made during evaluation episodes. command: python inference.py --benchmark --out results.json expected_output_format: | difficulty=easy avg_score=X.XXXX avg_reward=X.XXXX n=5 difficulty=medium avg_score=X.XXXX avg_reward=X.XXXX n=5 difficulty=hard avg_score=X.XXXX avg_reward=X.XXXX n=5 tier_validation: easy_avg > medium_avg > hard_avg runtime_budget: "< 20 minutes on 2 vCPU / 8 GB RAM" logging_protocol: "[START] / [STEP] / [END]" # --------------------------------------------------------------------------- # Data pipeline (dataset creation only — not used during eval) # --------------------------------------------------------------------------- data_pipeline: description: > DataCollector is used ONLY to build the static scenario datasets in tasks/{difficulty}/scenarios.json. It is NOT called during evaluation episodes. backends: - { name: serpapi, env_key: SERPAPI_KEY } - { name: newsapi, env_key: NEWSAPI_KEY } - { name: brave_search, env_key: BRAVE_SEARCH_KEY } - { name: google_factcheck, env_key: GOOGLE_FACTCHECK_KEY } - { name: duckduckgo, env_key: null, note: "No key required; rate-limited fallback" } cache: backend: redis env_key: REDIS_URL default: redis://localhost:6379 ttl_seconds: 86400 # --------------------------------------------------------------------------- # Constraints # --------------------------------------------------------------------------- constraints: - Ground truth is never exposed in the Observation - No external API calls occur during env.step() or env.reset() - All reward computations are deterministic - Agents must gather evidence before deciding (premature decision penalty applies) - Redundant actions (re-checking same id) are penalised - Scenario datasets are static JSON — reproducible across runs # --------------------------------------------------------------------------- # Baseline # --------------------------------------------------------------------------- baseline: script: inference.py mode: --benchmark agent_type: ReAct (LLM-driven) logging_protocol: "[START] / [STEP] / [END]" model_env_var: MODEL_NAME api_base_env_var: API_BASE_URL token_env_var: HF_TOKEN expected_scores: easy: { avg_score: "~0.78", avg_reward: "~1.20" } medium: { avg_score: "~0.63", avg_reward: "~0.90" } hard: { avg_score: "~0.52", avg_reward: "~0.65" }