explainer-env / models.py
kgdrathan's picture
Upload folder using huggingface_hub
b12f1bd verified
"""Data models for the Research -> Interactive Explainer environment."""
from typing import Any, Literal
from openenv.core.env_server.types import Action, Observation
from pydantic import Field
try:
from .constants import MAX_EXPLORE_STEPS, MAX_REPAIR_STEPS
except ImportError: # pragma: no cover - supports direct test execution
from constants import MAX_EXPLORE_STEPS, MAX_REPAIR_STEPS
ResearchTool = Literal[
"search_wikipedia",
"search_hf_papers",
"search_arxiv",
"search_scholar",
"fetch_docs",
"search_hf_hub",
]
class ExplainerAction(Action):
"""Action: agent explores, generates, or repairs an artifact."""
action_type: Literal["explore", "generate", "repair"] = Field(
...,
description="'explore' to research, 'generate' to produce code, 'repair' to fix code",
)
# -- explore fields --
tool: ResearchTool | None = Field(
default=None,
description="Research tool to call when action_type='explore'",
)
query: str = Field(
default="",
description="Research query used when action_type='explore'",
)
intent: str = Field(
default="",
description="Brief goal for the research call, e.g. equations or visual intuition",
)
# -- generate / repair fields --
format: Literal["marimo", "manim"] | None = Field(
default=None,
description="Output format (required for generate/repair)",
)
code: str = Field(
default="",
description="Complete Python source code (required for generate/repair)",
)
narration: str = Field(
default="",
description="Narration script (used when format='manim')",
)
repair_notes: str = Field(
default="",
description="Short explanation of what changed when action_type='repair'",
)
class ExplainerObservation(Observation):
"""Observation returned to the agent after each step."""
# -- task info (set on reset, echoed back each step) --
topic: str = Field(default="", description="Title of the topic or paper")
content: str = Field(default="", description="Abstract or concept description")
tier: Literal["beginner", "intermediate", "advanced"] = Field(
default="beginner", description="Explanation depth tier"
)
keywords: str = Field(default="", description="Comma-separated key terms")
data_available: bool = Field(
default=False, description="Whether the topic references datasets"
)
difficulty: Literal["easy", "medium", "hard"] = Field(
default="easy", description="Task difficulty tier"
)
# -- per-step feedback --
phase: Literal["explore", "generate", "repair", "done"] = Field(
default="explore", description="Current episode phase"
)
feedback: str = Field(default="", description="Feedback on the last action")
search_results: str = Field(
default="", description="Papers/snippets returned from an explore step"
)
top_chunks: list[dict[str, Any]] = Field(
default_factory=list,
description="Ranked top chunks returned from the last explore step",
)
explored_context: str = Field(
default="",
description="Accumulated research context from all explore steps so far",
)
explore_steps_left: int = Field(
default=MAX_EXPLORE_STEPS, description="Remaining explore steps before forced generate"
)
repair_attempts_left: int = Field(
default=MAX_REPAIR_STEPS, description="Remaining repair attempts after failed generation"
)
last_errors: str = Field(
default="", description="Latest lint/build errors available for repair"
)
available_tools: list[str] = Field(
default_factory=list, description="Research tools available during explore"
)