Class: ActionAgent::SandboxSession

Inherits:
ApplicationRecord show all
Includes:
Ownable
Defined in:
app/models/action_agent/sandbox_session.rb

Constant Summary collapse

SANDBOX_TYPES =

Sandbox types

%w[playwright_mcp terminal research].freeze
FREE_TIER_LIMITS =

Free tier limits

{
  max_runs: 10,
  timeout_seconds: 300,
  max_tokens: 50_000,
  session_duration_minutes: 15
}.freeze

Constants included from Ownable

Ownable::CLASS_FOR

Instance Method Summary collapse

Methods included from Ownable

#owner, #owner=

Methods inherited from ApplicationRecord

for_owner, owner_association

Instance Method Details

#active?Boolean

Check if session is still valid

Returns:

  • (Boolean)


55
56
57
# File 'app/models/action_agent/sandbox_session.rb', line 55

def active?
  !expired? && !failed? && !completed? && expires_at > Time.current
end

#can_run?Boolean

Check if can run more tasks

Returns:

  • (Boolean)


60
61
62
# File 'app/models/action_agent/sandbox_session.rb', line 60

def can_run?
  active? && runs_count < max_runs
end

#detailsObject

Detailed info including runs



140
141
142
143
144
145
146
# File 'app/models/action_agent/sandbox_session.rb', line 140

def details
  summary.merge(
    runs: runs,
    total_duration_ms: total_duration_ms,
    last_activity_at: last_activity_at&.iso8601
  )
end

#expire!Object

Expire the session



116
117
118
119
120
# File 'app/models/action_agent/sandbox_session.rb', line 116

def expire!
  update!(status: :expired)
  # Cleanup Cloud Run resources
  SandboxCleanupJob.perform_later(id) if cloud_run_job_id.present?
end

#mark_ready!(cloud_run_url:, cloud_run_job_id: nil) ⇒ Object

Mark as ready with Cloud Run URL



107
108
109
110
111
112
113
# File 'app/models/action_agent/sandbox_session.rb', line 107

def mark_ready!(cloud_run_url:, cloud_run_job_id: nil)
  update!(
    status: :ready,
    cloud_run_url: cloud_run_url,
    cloud_run_job_id: cloud_run_job_id
  )
end

#mcp_catalog_entriesObject

Catalog entries for the MCP servers this session was started with. Unknown keys are dropped rather than raising — a session outlives a catalog edit.



50
51
52
# File 'app/models/action_agent/sandbox_session.rb', line 50

def mcp_catalog_entries
  Array(mcp_servers).filter_map { |key| McpCatalog.find(key) }
end

#provision!Object

Provision the Cloud Run sandbox



93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/models/action_agent/sandbox_session.rb', line 93

def provision!
  return if provisioning? || ready?

  update!(status: :provisioning)

  # In development, run synchronously for immediate feedback
  if Rails.env.development? || Rails.env.test?
    SandboxProvisionJob.perform_now(id)
  else
    SandboxProvisionJob.perform_later(id)
  end
end

#record_run!(task:, result:, duration_ms:, tokens:, screenshots: [], provider: nil) ⇒ Object

Record a new run (thread-safe for parallel execution)



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
# File 'app/models/action_agent/sandbox_session.rb', line 65

def record_run!(task:, result:, duration_ms:, tokens:, screenshots: [], provider: nil)
  run = {
    id: SecureRandom.uuid,
    task: task,
    result: result,
    duration_ms: duration_ms,
    tokens: tokens,
    screenshots: screenshots,
    provider: provider,
    status: "completed",
    created_at: Time.current.iso8601
  }

  # Use pessimistic locking to prevent race conditions when multiple providers run in parallel
  with_lock do
    reload # Reload to get the latest state
    self.runs = runs + [ run ]
    self.runs_count = runs.size
    self.total_tokens += tokens
    self.total_duration_ms += duration_ms
    self.last_activity_at = Time.current
    save!
  end

  run
end

#summaryObject

Summary for API responses



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'app/models/action_agent/sandbox_session.rb', line 123

def summary
  {
    id: id,
    session_id: session_id,
    sandbox_type: sandbox_type,
    status: status,
    runs_count: runs_count,
    max_runs: max_runs,
    total_tokens: total_tokens,
    expires_at: expires_at&.iso8601,
    created_at: created_at.iso8601,
    cloud_run_url: cloud_run_url,
    mcp_servers: Array(mcp_servers)
  }
end