Class: ActionAgent::SessionRecording

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

Constant Summary

Constants included from Ownable

Ownable::CLASS_FOR

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Ownable

#owner, #owner=

Methods inherited from ApplicationRecord

for_owner, owner_association

Class Method Details

.generate_name(agent_run, sandbox_session) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
# File 'app/models/action_agent/session_recording.rb', line 139

def self.generate_name(agent_run, sandbox_session)
  prefix = if agent_run&.agent
    agent_run.agent.name.parameterize
  elsif sandbox_session&.agent_template
    sandbox_session.agent_template.name.parameterize
  else
    "session"
  end

  "#{prefix}_#{Time.current.strftime('%Y%m%d_%H%M%S')}"
end

.start!(agent_run: nil, sandbox_session: nil, name: nil) ⇒ Object

Start a new recording session



35
36
37
38
39
40
41
42
43
# File 'app/models/action_agent/session_recording.rb', line 35

def self.start!(agent_run: nil, sandbox_session: nil, name: nil)
  create!(
    agent_run: agent_run,
    sandbox_session: sandbox_session,
    name: name || generate_name(agent_run, sandbox_session),
    status: :recording,
    metadata: { started_at: Time.current.iso8601 }
  )
end

.start_user_session!(visitor_id: nil, parent_demo_id: nil, page_url: nil) ⇒ Object

Start a user takeover session (for lander demo analytics)



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/models/action_agent/session_recording.rb', line 46

def self.start_user_session!(visitor_id: nil, parent_demo_id: nil, page_url: nil)
  create!(
    name: "user_takeover_#{Time.current.strftime('%Y%m%d_%H%M%S')}_#{SecureRandom.hex(4)}",
    status: :recording,
    metadata: {
      started_at: Time.current.iso8601,
      session_type: "user_takeover",
      visitor_id: visitor_id,
      parent_demo_id: parent_demo_id,
      page_url: page_url,
      user_agent: nil # Will be set from request
    }
  )
end

Instance Method Details

#complete!Object

Complete the recording



91
92
93
94
95
96
97
98
99
# File 'app/models/action_agent/session_recording.rb', line 91

def complete!
  return unless recording?

  update!(
    status: :completed,
    duration_ms: elapsed_ms,
    metadata: .merge(completed_at: Time.current.iso8601)
  )
end

#demo_recording?Boolean

Check if this is a demo recording (doesn't require parent)

Returns:

  • (Boolean)


25
26
27
# File 'app/models/action_agent/session_recording.rb', line 25

def demo_recording?
  name&.start_with?("lander_") || name == "demo"
end

#fail!(error_message = nil) ⇒ Object

Mark recording as failed



102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/action_agent/session_recording.rb', line 102

def fail!(error_message = nil)
  return unless recording?

  update!(
    status: :failed,
    duration_ms: elapsed_ms,
    metadata: .merge(
      failed_at: Time.current.iso8601,
      error: error_message
    )
  )
end

#record_action!(action_type:, selector: nil, value: nil, screenshot: nil, dom_snapshot: nil, metadata: {}) ⇒ Object

Record a browser action



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

def record_action!(action_type:, selector: nil, value: nil, screenshot: nil, dom_snapshot: nil, metadata: {})
  raise "Recording already completed" unless recording?

  action = recording_actions.create!(
    action_type: action_type,
    sequence: next_sequence,
    timestamp_ms: elapsed_ms,
    selector: selector,
    value: value,
    metadata: 
  )

  # Handle screenshot attachment if provided
  if screenshot.present?
    snapshot = store_snapshot(screenshot, :screenshot, action)
    action.update!(screenshot_key: snapshot.storage_key)
  end

  # Handle DOM snapshot if provided
  if dom_snapshot.present?
    snapshot = store_snapshot(dom_snapshot, :dom, action)
    action.update!(dom_snapshot_key: snapshot.storage_key)
  end

  increment!(:action_count)
  action
end

#timelineObject

Get timeline data for playback



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'app/models/action_agent/session_recording.rb', line 116

def timeline
  recording_actions.order(:sequence).map do |action|
    {
      id: action.id,
      type: action.action_type,
      sequence: action.sequence,
      timestamp_ms: action.timestamp_ms,
      selector: action.selector,
      value: action.value,
      screenshot_key: action.screenshot_key,
      metadata: action.
    }
  end
end

#user_session?Boolean

Check if this is a user takeover session (doesn't require parent)

Returns:

  • (Boolean)


30
31
32
# File 'app/models/action_agent/session_recording.rb', line 30

def user_session?
  name&.start_with?("user_takeover_")
end