Class: ActionAgent::SandboxInstanceTier

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Attributes, ActiveModel::Model
Defined in:
app/models/action_agent/sandbox_instance_tier.rb

Overview

SandboxInstanceTier

Defines available instance sizes for sandbox sessions. Similar to Google Colab or Hugging Face Spaces hardware tiers.

Usage:

tier = SandboxInstanceTier.find(:gpu_t4)
tier.cpu_cores      # => 4
tier.memory_gb      # => 16
tier.gpu            # => "nvidia-t4"
tier.hourly_cost    # => 0.35

Constant Summary collapse

TIERS =

Instance tier definitions Pricing modeled after Colab/HuggingFace/Lambda Labs

{
  # --- Free Tier ---
  free: {
    id: "free",
    name: "Free",
    description: "Basic CPU instance for testing",
    cpu_cores: 2,
    memory_gb: 4,
    disk_gb: 10,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.00,
    monthly_cost: 0.00,
    category: "free"
  },

  # --- CPU Tiers ---
  cpu_small: {
    id: "cpu_small",
    name: "CPU Small",
    description: "2 vCPUs, 8GB RAM",
    cpu_cores: 2,
    memory_gb: 8,
    disk_gb: 20,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.05,
    monthly_cost: 36.00,
    category: "pro"
  },

  cpu_medium: {
    id: "cpu_medium",
    name: "CPU Medium",
    description: "4 vCPUs, 16GB RAM",
    cpu_cores: 4,
    memory_gb: 16,
    disk_gb: 50,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.10,
    monthly_cost: 72.00,
    category: "pro"
  },

  cpu_large: {
    id: "cpu_large",
    name: "CPU Large",
    description: "8 vCPUs, 32GB RAM",
    cpu_cores: 8,
    memory_gb: 32,
    disk_gb: 100,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.20,
    monthly_cost: 144.00,
    category: "pro"
  },

  cpu_xlarge: {
    id: "cpu_xlarge",
    name: "CPU XLarge",
    description: "16 vCPUs, 64GB RAM",
    cpu_cores: 16,
    memory_gb: 64,
    disk_gb: 200,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.40,
    monthly_cost: 288.00,
    category: "enterprise"
  },

  # --- GPU Tiers ---
  gpu_t4: {
    id: "gpu_t4",
    name: "GPU T4",
    description: "NVIDIA T4 (16GB VRAM), 4 vCPUs, 16GB RAM",
    cpu_cores: 4,
    memory_gb: 16,
    disk_gb: 50,
    gpu: "nvidia-tesla-t4",
    gpu_memory_gb: 16,
    hourly_cost: 0.35,
    monthly_cost: 252.00,
    category: "pro"
  },

  gpu_l4: {
    id: "gpu_l4",
    name: "GPU L4",
    description: "NVIDIA L4 (24GB VRAM), 8 vCPUs, 32GB RAM",
    cpu_cores: 8,
    memory_gb: 32,
    disk_gb: 100,
    gpu: "nvidia-l4",
    gpu_memory_gb: 24,
    hourly_cost: 0.70,
    monthly_cost: 504.00,
    category: "pro"
  },

  gpu_a10g: {
    id: "gpu_a10g",
    name: "GPU A10G",
    description: "NVIDIA A10G (24GB VRAM), 8 vCPUs, 32GB RAM",
    cpu_cores: 8,
    memory_gb: 32,
    disk_gb: 100,
    gpu: "nvidia-a10g",
    gpu_memory_gb: 24,
    hourly_cost: 1.00,
    monthly_cost: 720.00,
    category: "enterprise"
  },

  gpu_a100_40: {
    id: "gpu_a100_40",
    name: "GPU A100 40GB",
    description: "NVIDIA A100 (40GB VRAM), 12 vCPUs, 85GB RAM",
    cpu_cores: 12,
    memory_gb: 85,
    disk_gb: 200,
    gpu: "nvidia-a100-40gb",
    gpu_memory_gb: 40,
    hourly_cost: 2.50,
    monthly_cost: 1800.00,
    category: "enterprise"
  },

  gpu_a100_80: {
    id: "gpu_a100_80",
    name: "GPU A100 80GB",
    description: "NVIDIA A100 (80GB VRAM), 12 vCPUs, 170GB RAM",
    cpu_cores: 12,
    memory_gb: 170,
    disk_gb: 200,
    gpu: "nvidia-a100-80gb",
    gpu_memory_gb: 80,
    hourly_cost: 4.00,
    monthly_cost: 2880.00,
    category: "enterprise"
  },

  # --- High Memory Tiers ---
  highmem_medium: {
    id: "highmem_medium",
    name: "High Memory Medium",
    description: "4 vCPUs, 64GB RAM",
    cpu_cores: 4,
    memory_gb: 64,
    disk_gb: 100,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.25,
    monthly_cost: 180.00,
    category: "pro"
  },

  highmem_large: {
    id: "highmem_large",
    name: "High Memory Large",
    description: "8 vCPUs, 128GB RAM",
    cpu_cores: 8,
    memory_gb: 128,
    disk_gb: 200,
    gpu: nil,
    gpu_memory_gb: nil,
    hourly_cost: 0.50,
    monthly_cost: 360.00,
    category: "enterprise"
  }
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.allObject



210
211
212
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 210

def all
  TIERS.values.map { |attrs| new(attrs) }
end

.availableObject



221
222
223
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 221

def available
  all.select(&:available)
end

.by_category(category) ⇒ Object



225
226
227
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 225

def by_category(category)
  all.select { |t| t.category == category.to_s }
end

.cpu_tiersObject



229
230
231
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 229

def cpu_tiers
  all.select { |t| t.gpu.nil? }
end

.default_tierObject



241
242
243
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 241

def default_tier
  find(:cpu_small)
end

.find(id) ⇒ Object

Raises:

  • (ArgumentError)


214
215
216
217
218
219
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 214

def find(id)
  id = id.to_sym
  raise ArgumentError, "Unknown tier: #{id}" unless TIERS.key?(id)

  new(TIERS[id])
end

.free_tierObject



237
238
239
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 237

def free_tier
  find(:free)
end

.gpu_tiersObject



233
234
235
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 233

def gpu_tiers
  all.select { |t| t.gpu.present? }
end

Instance Method Details

#as_jsonObject



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 346

def as_json(*)
  {
    id: id,
    name: name,
    description: description,
    specs: {
      cpu_cores: cpu_cores,
      memory_gb: memory_gb,
      disk_gb: disk_gb,
      gpu: gpu,
      gpu_memory_gb: gpu_memory_gb
    },
    pricing: {
      hourly_cost: hourly_cost.to_f,
      monthly_cost: monthly_cost.to_f,
      display: display_price
    },
    category: category,
    available: available
  }
end

#display_priceObject



254
255
256
257
258
259
260
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 254

def display_price
  if free?
    "Free"
  else
    "$#{format('%.2f', hourly_cost)}/hr"
  end
end

#display_specsObject



262
263
264
265
266
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 262

def display_specs
  specs = [ "#{cpu_cores} vCPU", "#{memory_gb}GB RAM", "#{disk_gb}GB disk" ]
  specs << "#{gpu_memory_gb}GB #{gpu_display_name}" if has_gpu?
  specs.join(" | ")
end

#free?Boolean

Returns:

  • (Boolean)


246
247
248
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 246

def free?
  hourly_cost.zero?
end

#gcp_accelerator_configObject

GCP accelerator config



337
338
339
340
341
342
343
344
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 337

def gcp_accelerator_config
  return nil unless has_gpu?

  {
    accelerator_type: gpu,
    accelerator_count: 1
  }
end

#gcp_machine_typeObject

GCP machine type mapping



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 319

def gcp_machine_type
  if has_gpu?
    # GPU instances use n1 or a2 series
    case gpu
    when "nvidia-a100-40gb", "nvidia-a100-80gb"
      "a2-highgpu-1g"
    else
      "n1-standard-#{cpu_cores}"
    end
  elsif memory_gb > cpu_cores * 8
    # High memory ratio
    "n2-highmem-#{cpu_cores}"
  else
    "n2-standard-#{cpu_cores}"
  end
end

#gpu_display_nameObject



268
269
270
271
272
273
274
275
276
277
278
279
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 268

def gpu_display_name
  return nil unless gpu

  case gpu
  when "nvidia-tesla-t4" then "T4"
  when "nvidia-l4" then "L4"
  when "nvidia-a10g" then "A10G"
  when "nvidia-a100-40gb" then "A100 40GB"
  when "nvidia-a100-80gb" then "A100 80GB"
  else gpu.gsub("nvidia-", "").upcase
  end
end

#has_gpu?Boolean

Returns:

  • (Boolean)


250
251
252
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 250

def has_gpu?
  gpu.present?
end

#to_incus_limitsObject

Convert to Incus resource limits



282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 282

def to_incus_limits
  limits = {
    "limits.cpu" => cpu_cores.to_s,
    "limits.memory" => "#{memory_gb}GB",
    "limits.processes" => (cpu_cores * 250).to_s
  }

  # GPU passthrough requires host configuration
  if has_gpu?
    limits["nvidia.runtime"] = "true"
    limits["nvidia.require.cuda"] = "true"
  end

  limits
end

#to_kubernetes_resourcesObject

Convert to Kubernetes resource spec



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'app/models/action_agent/sandbox_instance_tier.rb', line 299

def to_kubernetes_resources
  resources = {
    requests: {
      cpu: "#{cpu_cores * 500}m",
      memory: "#{memory_gb / 2}Gi"
    },
    limits: {
      cpu: cpu_cores.to_s,
      memory: "#{memory_gb}Gi"
    }
  }

  if has_gpu?
    resources[:limits]["nvidia.com/gpu"] = "1"
  end

  resources
end