Spaces:
No application file
No application file
| """ | |
| CarbonSchedulerEnv โ Action and Observation models. | |
| Both inherit from OpenEnv base types so the framework can | |
| auto-generate schemas, WebSocket handlers, and the web UI. | |
| Action: | |
| Structured list of scheduling decisions โ one per pending job. | |
| Each decision is either an assignment (region + start_hour) or a defer. | |
| Observation: | |
| Full state of the scheduling problem โ text prompt included so | |
| the LLM can consume it directly via `obs.prompt`. | |
| """ | |
| from typing import Dict, List, Optional | |
| from pydantic import Field | |
| from openenv.core.env_server.types import Action, Observation | |
| class ScheduleDecision(Action): | |
| """One scheduling decision for a single job.""" | |
| job_id: str = Field(..., description="ID of the job being scheduled") | |
| region: str = Field( | |
| default="", | |
| description="Target data centre region (e.g. 'us-west-2'). Empty if deferring.", | |
| ) | |
| start_hour: int = Field( | |
| default=-1, | |
| description="UTC hour to start the job (0โ23). -1 if deferring.", | |
| ) | |
| defer: bool = Field( | |
| default=False, | |
| description="True to defer this job to the next scheduling step.", | |
| ) | |
| class CarbonSchedulerAction(Action): | |
| """ | |
| Agent's full scheduling action for one step. | |
| The agent outputs a list of decisions โ one per pending job. | |
| Each job must be either assigned (region + start_hour) or deferred. | |
| Example: | |
| { | |
| "assignments": [ | |
| {"job_id": "job_01", "region": "us-west-2", "start_hour": 14}, | |
| {"job_id": "job_02", "defer": true}, | |
| {"job_id": "job_03", "region": "eu-west-1", "start_hour": 16} | |
| ], | |
| "reasoning": "Deferring job_02 to the solar window at 14:00 in Oregon" | |
| } | |
| """ | |
| assignments: List[ScheduleDecision] = Field( | |
| default_factory=list, | |
| description="List of scheduling decisions โ one per pending job.", | |
| ) | |
| reasoning: str = Field( | |
| default="", | |
| description="Optional: agent's reasoning for this schedule (for interpretability).", | |
| ) | |
| class CarbonSchedulerObservation(Observation): | |
| """ | |
| Full observation of the scheduling environment. | |
| Key fields for the LLM agent: | |
| prompt โ formatted text prompt ready for LLM consumption | |
| current_hour โ current UTC hour (0โ23) | |
| jobs_pending โ list of jobs awaiting scheduling | |
| datacenters โ list of data centres with carbon forecasts | |
| carbon_saved_so_far โ gCO2 saved vs naive baseline this episode | |
| Key fields for training: | |
| reward โ reward from the last step | |
| done โ True if episode is over | |
| reward_breakdown โ per-component reward for interpretability | |
| """ | |
| # โโ Episode metadata โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| current_hour: int = Field(default=0, description="Current UTC hour (0โ23)") | |
| step_number: int = Field(default=0, description="Step index within episode") | |
| done: bool = Field(default=False) | |
| reward: float = Field(default=0.0) | |
| # โโ Scheduling state โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| jobs_pending: List[dict] = Field( | |
| default_factory=list, | |
| description="Jobs awaiting a scheduling decision this step.", | |
| ) | |
| jobs_completed: int = Field(default=0) | |
| jobs_failed: int = Field(default=0) | |
| total_jobs: int = Field(default=0) | |
| # โโ Data centres โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| datacenters: List[dict] = Field( | |
| default_factory=list, | |
| description="Data centre state including carbon forecast for next 12 hours.", | |
| ) | |
| # โโ Progress metrics โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| carbon_saved_so_far: float = Field( | |
| default=0.0, | |
| description="gCO2 saved vs naive run-immediately baseline this episode.", | |
| ) | |
| naive_carbon_so_far: float = Field( | |
| default=0.0, | |
| description="Carbon that naive scheduler would have emitted.", | |
| ) | |
| actual_carbon_so_far: float = Field( | |
| default=0.0, | |
| description="Actual carbon emitted by agent's schedule so far.", | |
| ) | |
| completion_rate: float = Field( | |
| default=0.0, | |
| description="Fraction of jobs completed (0.0โ1.0).", | |
| ) | |
| # โโ Curriculum โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| curriculum_stage: int = Field( | |
| default=1, | |
| description="Current curriculum level (1=easy, 2=medium, 3=hard).", | |
| ) | |
| # โโ Reward breakdown (for training interpretability) โโโโโโโโโโโโโโโโโโโ | |
| reward_breakdown: Dict[str, float] = Field( | |
| default_factory=dict, | |
| description="Per-component reward breakdown for this step.", | |
| ) | |
| episode_summary: Dict[str, float] = Field( | |
| default_factory=dict, | |
| description="End-of-episode metrics (populated when done=True).", | |
| ) | |
| # โโ LLM prompt โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| prompt: str = Field( | |
| default="", | |
| description="Formatted text prompt for LLM consumption โ ready to use directly.", | |
| ) | |