Execute

Run an RL action and advance one step

Executes an agent action, simulates one time step, and returns the next observation, reward, and episode completion status. This is the core training loop interaction.

Idle TTL: Each successful step call resets the environment's 2-hour idle timer. Environments that receive no step or reset calls for 2 hours are automatically deactivated and their linked simulation artifacts removed. Subsequent requests to a deactivated environment return 404. Call step or reset at least once every 2 hours during long training runs to keep the environment alive.

post/rl/environments/{environmentId}/step

Request

  • Base URL: https://www.cloudworldmodel.ai/api
  • URL: https://www.cloudworldmodel.ai/api/rl/environments/{environmentId}/step
  • Auth: one of:
    • HTTP bearer
    • API key in header X-PAYMENT
    • API key in header PAYMENT-SIGNATURE

Path parameters

environmentIdstring uuid required

ID of the RL environment

Request body

tick_secondsinteger

Per-step override for the simulation clock advancement. When provided, this value overrides the episode-level tick_seconds set in episodeConfig for this step only. Useful for agents that want to fast-forward through warm-up phases (e.g. 300 s ticks) and then switch to finer-grained steps (e.g. 60 s ticks) for precise autoscaling decisions. The actual value used is reflected in observation.tick_seconds in the response.

Example request

{
  "action": {
    "type": "scale_out",
    "parameters": {
      "instanceCount": 1
    }
  }
}

Response

Step executed successfully

tinteger required

Current simulation time step (incremented after each action)

rewardnumber required

Scalar total reward for this step (weighted sum of reward_components)

doneboolean required

Whether the episode is complete

sim_time_humanstring required

Human-readable representation of the elapsed simulated time. Format is Xh Ym when at least one hour has elapsed, Xm Ys when at least one minute (but less than one hour) has elapsed, and Xs for less than one minute. Mirrors the value inside info.sim_time_human for convenient top-level access without unpacking the info object.

unmodeled_cost_warningstring[]

List of cost dimension identifiers that are active this step but not modeled in the reward function. Present (and non-empty) only when at least one unmodeled dimension is detected. Omitted when all detected dimensions are modeled. Known values: egress (network egress charges are incurred whenever traffic > 0), cross_az_traffic (cross-AZ data transfer charges apply when resources with different availability zones are connected).

unmodeled_cost_penaltynumber

Total reward penalty applied this step due to unmodeled cost dimensions. Equals -(count of active unmodeled dimensions × episodeConfig.unmodeled_cost_penalty_per_dimension). Present only when unmodeled_cost_warning is non-empty.

Example response

{
  "t": 15,
  "obs": {
    "rps": 1620,
    "cpu_util": 0.582,
    "instances": 3,
    "traffic": 1620,
    "currentTime": 15,
    "tick_seconds": 60,
    "unmodeled_dimensions_active": true,
    "warmup_factor": 0.5,
    "routedRps_per_node": 583.3,
    "unavailable_node_count": 1
  },
  "metrics": {
    "cost_usd_hr": 1.08,
    "latency_p95": 104,
    "error_rate": 0.003,
    "uptime": 0.997,
    "connection_pressure": 1.25,
    "compute": [
      {
        "warmup_factor": 0.5,
        "warmup_steps_remaining": 2
      }
    ],
    "error_breakdown": {
      "db_failure": 24
    },
    "ttft_p50_ms": 245,
    "decode_tokens_per_sec": 3840
  },
  "resources": [
    {
      "id": "ec2-1",
      "type": "compute",
      "name": "Web Server 1",
      "provider": "aws",
      "location": {
        "regionKey": "us-east-2"
      },
      "characteristics": {
        "workload": "crud",
        "appRuntime": "node",
        "appWorkerCount": 2,
        "appDbPoolSize": 250,
        "workloadDatabaseVersion": "8.0",
        "workloadDatabaseEngine": "mysql",
        "rdsSqlServerBilling": {
          "instanceClass": "db.t3.micro",
          "storageType": "gp2",
          "allocatedStorageGiB": 20,
          "durationHours": 480,
          "sustainedCpuPercent": 43
        },
        "serviceFamily": "ec2",
        "containerCpu": 0.5,
        "containerMemoryGiB": 1,
        "runtimeMemoryProfile": {
          "workingSetGiB": 0.78125
        },
        "concurrency": 80,
        "requestDurationSeconds": 0.25,
        "requestServingTargetUtilizationPct": 70,
        "billingState": "stopped",
        "size": "m5.large",
        "instanceType": "t3.medium",
        "ocpus": 4,
        "maxThroughput": 2000,
        "capacityRps": 100,
        "baseLatency": 3,
        "maxConnections": 800,
        "capacityGB": 500,
        "maxIops": 3000,
        "inferenceMode": true,
        "accelerator": "a10g",
        "managedComputePlatform": "nvidia-dgx-cloud",
        "openshiftOffering": "rosa-hcp",
        "topology": {
          "intraNode": "nvlink-nvswitch",
          "interNode": "infiniband"
        },
        "intraNode": "nvlink-nvswitch",
        "interNode": "infiniband",
        "includesControlPlane": true,
        "bundledNetworking": true,
        "trainingMode": true,
        "tokensPerRequest": 500,
        "inputTokensPerRequest": 1000,
        "cacheHitRate": 0.85,
        "cacheableRequestShare": 0.75,
        "asynchronousRequestShare": 0.15,
        "queueConsumerCount": 4,
        "queueDrainRatePerConsumerRps": 125,
        "queueCapacityMessages": 20000,
        "queueSimulationStepSeconds": 1,
        "autoscaling": true,
        "maxInstances": 5,
        "minInstances": 2,
        "scaleOutCpuThreshold": 60,
        "scaleInCpuThreshold": 25,
        "nodeCount": 2,
        "workerVcpu": 4,
        "minNodes": 2,
        "maxNodes": 10,
        "perNodeRate": 3.2,
        "pricingModel": "on-demand",
        "nodePools": [
          {
            "name": "general",
            "nodeCount": 2,
            "workerVcpu": 8,
            "minNodes": 2,
            "maxNodes": 10,
            "perNodeRate": 0.096,
            "maxThroughput": 10000
          }
        ],
        "streamShardsCount": 4,
        "streamWriteRps": 3500,
        "eventNotificationsEnabled": true,
        "partitionCount": 8,
        "streamPartitions": 4,
        "partitionWriteRps": 5000,
        "warmupSteps": 5,
        "warmupSeverity": 0.8
      },
      "routedRps": 15,
      "availabilityState": "available",
      "isRoutable": true,
      "failureParkStepsRemaining": 3,
      "recoveryPolicy": {
        "criticalCpuThreshold": 75,
        "criticalSteps": 2,
        "warningCpuThreshold": 60,
        "warningSteps": 1,
        "failureParkSteps": 2
      }
    }
  ],
  "reward": 0.481,
  "reward_components": {
    "performance": 0.812,
    "cost": 0.924,
    "stability": -0.1,
    "connection_pressure": -0.3,
    "unmodeled_cost": -0.2
  },
  "sim_time_human": "15s",
  "info": {
    "sim_time_human": "1h 0m",
    "scale_clamped": true,
    "requested": 10,
    "actual": 2,
    "limit": 3
  },
  "tradeoffSummary": {
    "costDeltaPercent": -18.5,
    "costDirection": "improved",
    "latencyP95DeltaMs": -22,
    "latencyP95Direction": "improved",
    "resilienceDeltaScore": 0.0015,
    "resilienceDirection": "improved"
  },
  "unmodeled_cost_warning": [
    "egress",
    "cross_az_traffic"
  ],
  "unmodeled_cost_penalty": -0.2
}

Changes

No recorded changes to this operation across all 1 revision of this API.