File size: 7,113 Bytes
585cd37
 
 
 
 
 
 
a0b8672
585cd37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
"""OpenEnv type definitions for the Fish Farm environment.

FarmAction: What the agent can do each hour
FarmObservation: What the agent sees (partial observability — no ground truth disease state)
FarmState: Full internal state (for grading)
"""

from typing import Any, Dict, List
from openenv.core.env_server import Action, Observation, State
from pydantic import Field


class FarmAction(Action):
    """Agent's hourly farm management decision."""

    feeding_rate: float = Field(
        default=0.3, ge=0.0, le=1.0,
        description="Feeding intensity (0=none, 0.3=conservative, 0.5=normal, 1.0=maximum ration). "
                    "Higher feeding grows fish faster but produces more ammonia and consumes more oxygen."
    )
    aeration_rate: float = Field(
        default=0.5, ge=0.0, le=1.0,
        description="Aerator power (0=off, 0.5=half, 1.0=full). "
                    "Increases dissolved oxygen but costs electricity."
    )
    heater_setting: float = Field(
        default=0.0, ge=-1.0, le=1.0,
        description="Temperature control (-1.0=max cooling, 0=off, 1.0=max heating). "
                    "Adjusts water temperature toward optimal growth range."
    )
    water_exchange_rate: float = Field(
        default=0.02, ge=0.0, le=0.10,
        description="Fresh water exchange (0=none, 0.05=5%/hour, 0.10=10%/hour max). "
                    "Dilutes ammonia and refreshes oxygen but costs water."
    )
    harvest_decision: bool = Field(
        default=False,
        description="Set True to harvest all fish and end the episode. "
                    "Revenue depends on total biomass and market price."
    )
    treatment: str = Field(
        default="none",
        description="Disease treatment: 'none', 'antibiotics' (speeds recovery, harms biofilter), "
                    "'salt' (reduces nitrite toxicity), 'probiotics' (boosts biofilter), "
                    "'vaccination' ($100, prevents 80% of future infections). "
                    "Treatments cost money."
    )


class FarmObservation(Observation):
    """What the agent observes after each step.

    Note: Disease infection count is NOT directly visible — the agent must
    infer disease from behavioral indicators (feeding response, mortality spikes).
    """

    # Fish status
    avg_fish_weight: float = Field(default=5.0, description="Average individual fish weight (grams)")
    population: int = Field(default=10000, description="Total fish count in tank")
    mortality_today: int = Field(default=0, description="Fish deaths in the last 24 hours")
    cumulative_mortality: int = Field(default=0, description="Total deaths since stocking")
    survival_rate: float = Field(default=1.0, description="Fraction of original population still alive")
    stress_level: float = Field(default=0.0, description="Fish stress index (0.0=calm, 1.0=critical)")
    feeding_response: str = Field(default="normal", description="Fish appetite: eager/normal/sluggish/refusing")
    biomass_kg: float = Field(default=50.0, description="Total fish biomass in kg")
    growth_rate_g_day: float = Field(default=0.0, description="Current growth rate (g/day)")
    fcr: float = Field(default=0.0, description="Feed conversion ratio (kg feed / kg gain). Target <2.0")
    sgr: float = Field(default=0.0, description="Specific growth rate (%/day)")
    stocking_density: float = Field(default=50.0, description="Fish per cubic meter")

    # Water quality
    temperature: float = Field(default=28.0, description="Water temperature (Celsius)")
    dissolved_oxygen: float = Field(default=7.0, description="Dissolved oxygen (mg/L). Below 3=danger, below 1=lethal")
    ph: float = Field(default=7.5, description="Water pH (6.5-8.5 optimal)")
    ammonia: float = Field(default=0.1, description="Total ammonia nitrogen TAN (mg/L). Above 2=dangerous")
    ammonia_toxic: float = Field(default=0.005, description="Unionized ammonia UIA (mg/L). Above 0.05=toxic")
    nitrite: float = Field(default=0.05, description="Nitrite NO2 (mg/L). Above 0.5=stress")
    nitrate: float = Field(default=0.0, description="Nitrate NO3 (mg/L). Product of nitrification")
    water_quality_score: float = Field(default=1.0, description="Composite water quality (0-1)")
    algae_bloom: bool = Field(default=False, description="Is algae bloom active (DO swings)")
    nighttime_do_risk: float = Field(default=0.0, description="Nighttime DO crash risk (0=safe, 1=imminent). Increase aeration if high.")

    # System status
    aerator_working: bool = Field(default=True, description="Is the aerator functioning?")
    biofilter_working: bool = Field(default=True, description="Is the biofilter functioning?")
    heater_working: bool = Field(default=True, description="Is the heater functioning?")
    feed_remaining_kg: float = Field(default=500.0, description="Feed inventory remaining (kg)")

    # Economics
    current_fish_value: float = Field(default=0.0, description="Current market value of all fish ($)")
    total_cost_so_far: float = Field(default=0.0, description="Cumulative operating cost ($)")
    current_profit: float = Field(default=0.0, description="Revenue - costs if harvested now ($)")
    feed_price_per_kg: float = Field(default=0.50, description="Current feed price (stochastic, $/kg)")
    market_price_multiplier: float = Field(default=1.0, description="Seasonal market price factor (1.0=normal)")
    marginal_cost_per_hour: float = Field(default=0.0, description="Cost of last hour of operation ($)")
    roi_pct: float = Field(default=0.0, description="Return on investment (%)")

    # Weather
    weather_forecast: str = Field(default="", description="Current weather conditions")
    is_daytime: bool = Field(default=True, description="Is it daytime (affects photosynthesis/DO)")
    storm_active: bool = Field(default=False, description="Is a storm currently active")
    humidity: float = Field(default=75.0, description="Relative humidity (%)")

    # Context
    day_in_cycle: int = Field(default=0, description="Days since stocking")
    time_of_day: int = Field(default=0, description="Hour (0-23)")
    day_of_year: int = Field(default=1, description="Calendar day (1-365, for seasonal context)")
    alerts: List[str] = Field(default_factory=list, description="Active alerts and warnings")

    # Disease signals (partial observability — no infection count, but behavioral indicators)
    disease_suspected: bool = Field(default=False, description="Behavioral signs suggest disease (mortality+appetite)")

    # Env standard
    feedback: str = Field(default="", description="Narrative feedback on the current situation")


class FarmState(State):
    """Full internal state — used by graders, NOT visible to agent.

    Contains ground truth disease status, exact biochemistry, etc.
    """

    task_id: str = Field(default="", description="Current task ID")
    is_complete: bool = Field(default=False)
    final_score: float = Field(default=0.0)
    max_hours: int = Field(default=168)

    # Full simulator snapshot
    sim_state: Dict[str, Any] = Field(default_factory=dict)