Cloud-DevOps-RLEnv / models.py
SidhaGarg's picture
Add action-cost RL dynamics, metadata lookup, and hard-mode cascading failures
d35c04a
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
"""
Data models for the Cloud Devops Env Environment.
The cloud_devops_env environment simulates cloud/devops incident response tasks.
"""
import json
from typing import Any, Dict, Literal, Optional
from openenv.core.env_server.types import Action, Observation, State
from pydantic import Field, field_validator
class CloudAction(Action):
"""Action space (what the agent can do)."""
command: Literal[
"list_resources",
"describe_resource",
"view_logs",
"query_metadata",
"update_security_group",
"restart_service",
"submit_solution",
] = Field(..., description="The cloud API command to execute.")
resource_id: Optional[str] = Field(
default=None,
description=(
"The ID of the target resource (e.g., 'i-12345'). "
"Required for most commands except list_resources and query_metadata."
),
)
parameters: Optional[Dict[str, Any]] = Field(
default=None,
description=(
"Key-value pairs for updates "
"(e.g., {'port': '80', 'action': 'allow'} for update_security_group, "
"or {'ip_address': '10.0.4.5'} for query_metadata)."
),
)
message: Optional[str] = Field(
default=None,
description="Legacy field from template env; safe to remove after server/client migration.",
)
@field_validator("parameters", mode="before")
@classmethod
def _coerce_parameters(cls, value: Any) -> Any:
"""Allow /web text input to pass JSON for dict parameters."""
if value is None or value == "":
return None
if isinstance(value, dict):
return value
if isinstance(value, str):
try:
parsed = json.loads(value)
except json.JSONDecodeError as exc:
raise ValueError(
"parameters must be a JSON object string, e.g. {\"port\":80,\"action\":\"allow\"}"
) from exc
if not isinstance(parsed, dict):
raise ValueError("parameters JSON must decode to an object/dictionary")
return parsed
raise ValueError("parameters must be a dictionary or JSON object string")
class CloudObservation(Observation):
"""Observation space (what the agent sees)."""
output: str = Field(
...,
description="The terminal/API response from the last command executed.",
)
error: Optional[str] = Field(
default=None,
description="Error message if the last command failed or was invalid.",
)
system_health_status: str = Field(
...,
description="Current status of the system (e.g., 'CRITICAL', 'DEGRADED', 'HEALTHY').",
)
echoed_message: Optional[str] = Field(
default=None,
description="Legacy field from template env; safe to remove after server/client migration.",
)
message_length: int = Field(
default=0,
description="Legacy field from template env; safe to remove after server/client migration.",
)
class CloudState(State):
"""State space (the hidden environment state)."""
task_difficulty: str = Field(..., description="Current task: easy, medium, or hard.")
resources: Dict[str, Dict[str, Any]] = Field(
...,
description="The hidden JSON state of all mock cloud resources.",
)
step_count: int = Field(..., description="Number of actions taken so far.")
is_resolved: bool = Field(
...,
description="Whether the root cause has been successfully fixed.",
)
# Backward-compatible aliases for scaffolded files that still use template names.
CloudDevopsAction = CloudAction
CloudDevopsObservation = CloudObservation