garima-mahato's picture
Upload 17 files
a1c701e verified
Raw
History Blame Contribute Delete
5.97 kB
"""
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.",
)