Class: ActionAgent::SessionRecordingService
- Inherits:
-
Object
- Object
- ActionAgent::SessionRecordingService
- Defined in:
- app/services/action_agent/session_recording_service.rb
Overview
Service for managing browser session recordings Captures agent browser interactions for replay and handoff to human users
Defined Under Namespace
Classes: RecordingError
Instance Attribute Summary collapse
-
#recording ⇒ Object
readonly
Returns the value of attribute recording.
Class Method Summary collapse
-
.fetch_snapshot(storage_key) ⇒ Object
Class method: Fetch snapshot content.
-
.for_context(agent_run: nil, sandbox_session: nil) ⇒ Object
Find or create a recording for a context.
-
.signed_url_for(storage_key, expires_in: 15.minutes) ⇒ Object
Class method: Generate signed URL for stored snapshot.
-
.start(agent_run: nil, sandbox_session: nil, name: nil) ⇒ Object
Start a new recording session.
Instance Method Summary collapse
-
#capture_handoff_state(url:, cookies: nil, local_storage: nil, session_storage: nil, form_values: nil) ⇒ Object
Capture browser state for handoff.
-
#capture_snapshot(screenshot: nil, dom: nil, full_page: false) ⇒ Object
Capture a manual snapshot (screenshot + DOM).
-
#click(selector:, screenshot: nil, metadata: {}) ⇒ Object
Record a click action.
-
#complete! ⇒ Object
Complete the recording.
-
#dialog(accept:, text: nil, screenshot: nil) ⇒ Object
Record a dialog interaction.
-
#evaluate(function:, result: nil, screenshot: nil) ⇒ Object
Record a JavaScript evaluation.
-
#fail!(error_message = nil) ⇒ Object
Mark recording as failed.
-
#file_upload(paths:, screenshot: nil) ⇒ Object
Record a file upload.
-
#fill_form(fields:, screenshot: nil) ⇒ Object
Record a form fill (multiple fields).
-
#handoff_state ⇒ Object
Get handoff state for resuming session.
-
#hover(selector:, screenshot: nil) ⇒ Object
Record a hover action.
-
#initialize(recording = nil) ⇒ SessionRecordingService
constructor
A new instance of SessionRecordingService.
-
#key_press(key:, screenshot: nil) ⇒ Object
Record a key press.
-
#navigate(url:, screenshot: nil) ⇒ Object
Record a browser navigation.
-
#scroll(position:, screenshot: nil) ⇒ Object
Record a scroll action.
-
#select_option(selector:, values:, screenshot: nil) ⇒ Object
Record a select option action.
-
#timeline ⇒ Object
Get the recording timeline for playback.
-
#type(selector:, text:, screenshot: nil, metadata: {}) ⇒ Object
Record a type/input action.
Constructor Details
#initialize(recording = nil) ⇒ SessionRecordingService
Returns a new instance of SessionRecordingService.
11 12 13 |
# File 'app/services/action_agent/session_recording_service.rb', line 11 def initialize(recording = nil) @recording = recording end |
Instance Attribute Details
#recording ⇒ Object (readonly)
Returns the value of attribute recording.
9 10 11 |
# File 'app/services/action_agent/session_recording_service.rb', line 9 def recording @recording end |
Class Method Details
.fetch_snapshot(storage_key) ⇒ Object
Class method: Fetch snapshot content
202 203 204 205 206 207 208 209 210 |
# File 'app/services/action_agent/session_recording_service.rb', line 202 def self.fetch_snapshot(storage_key) snapshot = RecordingSnapshot.find_by(storage_key: storage_key) return nil unless snapshot&.file&.attached? snapshot.file.download rescue StandardError => e Rails.logger.error "Failed to fetch snapshot #{storage_key}: #{e.}" nil end |
.for_context(agent_run: nil, sandbox_session: nil) ⇒ Object
Find or create a recording for a context
27 28 29 30 31 32 33 34 |
# File 'app/services/action_agent/session_recording_service.rb', line 27 def self.for_context(agent_run: nil, sandbox_session: nil) recording = SessionRecording.recording.find_by( agent_run: agent_run, sandbox_session: sandbox_session ) recording ? new(recording) : start(agent_run: agent_run, sandbox_session: sandbox_session) end |
.signed_url_for(storage_key, expires_in: 15.minutes) ⇒ Object
Class method: Generate signed URL for stored snapshot
196 197 198 199 |
# File 'app/services/action_agent/session_recording_service.rb', line 196 def self.signed_url_for(storage_key, expires_in: 15.minutes) snapshot = RecordingSnapshot.find_by(storage_key: storage_key) snapshot&.signed_url(expires_in: expires_in) end |
.start(agent_run: nil, sandbox_session: nil, name: nil) ⇒ Object
Start a new recording session
16 17 18 19 20 21 22 23 24 |
# File 'app/services/action_agent/session_recording_service.rb', line 16 def self.start(agent_run: nil, sandbox_session: nil, name: nil) recording = SessionRecording.start!( agent_run: agent_run, sandbox_session: sandbox_session, name: name ) new(recording) end |
Instance Method Details
#capture_handoff_state(url:, cookies: nil, local_storage: nil, session_storage: nil, form_values: nil) ⇒ Object
Capture browser state for handoff
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'app/services/action_agent/session_recording_service.rb', line 158 def capture_handoff_state(url:, cookies: nil, local_storage: nil, session_storage: nil, form_values: nil) @recording.update!( metadata: @recording..merge( handoff_state: { url: url, cookies: , local_storage: local_storage, session_storage: session_storage, form_values: form_values, captured_at: Time.current.iso8601 } ) ) end |
#capture_snapshot(screenshot: nil, dom: nil, full_page: false) ⇒ Object
Capture a manual snapshot (screenshot + DOM)
146 147 148 149 150 151 152 153 154 155 |
# File 'app/services/action_agent/session_recording_service.rb', line 146 def capture_snapshot(screenshot: nil, dom: nil, full_page: false) snapshot_type = full_page ? "full_page" : "snapshot" record_action( action_type: "snapshot", screenshot: screenshot, dom_snapshot: dom, metadata: { full_page: full_page } ) end |
#click(selector:, screenshot: nil, metadata: {}) ⇒ Object
Record a click action
47 48 49 50 51 52 53 54 |
# File 'app/services/action_agent/session_recording_service.rb', line 47 def click(selector:, screenshot: nil, metadata: {}) record_action( action_type: "click", selector: selector, screenshot: screenshot, metadata: .merge(element: selector) ) end |
#complete! ⇒ Object
Complete the recording
174 175 176 177 |
# File 'app/services/action_agent/session_recording_service.rb', line 174 def complete! @recording.complete! @recording end |
#dialog(accept:, text: nil, screenshot: nil) ⇒ Object
Record a dialog interaction
126 127 128 129 130 131 132 133 |
# File 'app/services/action_agent/session_recording_service.rb', line 126 def dialog(accept:, text: nil, screenshot: nil) record_action( action_type: "dialog", value: text, screenshot: screenshot, metadata: { accepted: accept, prompt_text: text } ) end |
#evaluate(function:, result: nil, screenshot: nil) ⇒ Object
Record a JavaScript evaluation
136 137 138 139 140 141 142 143 |
# File 'app/services/action_agent/session_recording_service.rb', line 136 def evaluate(function:, result: nil, screenshot: nil) record_action( action_type: "evaluate", value: function, screenshot: screenshot, metadata: { result: result&.to_s&.truncate(1000) } ) end |
#fail!(error_message = nil) ⇒ Object
Mark recording as failed
180 181 182 183 |
# File 'app/services/action_agent/session_recording_service.rb', line 180 def fail!( = nil) @recording.fail!() @recording end |
#file_upload(paths:, screenshot: nil) ⇒ Object
Record a file upload
116 117 118 119 120 121 122 123 |
# File 'app/services/action_agent/session_recording_service.rb', line 116 def file_upload(paths:, screenshot: nil) record_action( action_type: "file_upload", value: paths.join(", "), screenshot: screenshot, metadata: { paths: paths } ) end |
#fill_form(fields:, screenshot: nil) ⇒ Object
Record a form fill (multiple fields)
68 69 70 71 72 73 74 75 |
# File 'app/services/action_agent/session_recording_service.rb', line 68 def fill_form(fields:, screenshot: nil) record_action( action_type: "form_fill", value: fields.to_json, screenshot: screenshot, metadata: { fields: fields, field_count: fields.size } ) end |
#handoff_state ⇒ Object
Get handoff state for resuming session
191 192 193 |
# File 'app/services/action_agent/session_recording_service.rb', line 191 def handoff_state @recording.["handoff_state"] end |
#hover(selector:, screenshot: nil) ⇒ Object
Record a hover action
96 97 98 99 100 101 102 |
# File 'app/services/action_agent/session_recording_service.rb', line 96 def hover(selector:, screenshot: nil) record_action( action_type: "hover", selector: selector, screenshot: screenshot ) end |
#key_press(key:, screenshot: nil) ⇒ Object
Record a key press
78 79 80 81 82 83 84 |
# File 'app/services/action_agent/session_recording_service.rb', line 78 def key_press(key:, screenshot: nil) record_action( action_type: "key_press", value: key, screenshot: screenshot ) end |
#navigate(url:, screenshot: nil) ⇒ Object
Record a browser navigation
37 38 39 40 41 42 43 44 |
# File 'app/services/action_agent/session_recording_service.rb', line 37 def navigate(url:, screenshot: nil) record_action( action_type: "navigate", value: url, screenshot: screenshot, metadata: { url: url } ) end |
#scroll(position:, screenshot: nil) ⇒ Object
Record a scroll action
87 88 89 90 91 92 93 |
# File 'app/services/action_agent/session_recording_service.rb', line 87 def scroll(position:, screenshot: nil) record_action( action_type: "scroll", metadata: { scroll_position: position }, screenshot: screenshot ) end |
#select_option(selector:, values:, screenshot: nil) ⇒ Object
Record a select option action
105 106 107 108 109 110 111 112 113 |
# File 'app/services/action_agent/session_recording_service.rb', line 105 def select_option(selector:, values:, screenshot: nil) record_action( action_type: "select", selector: selector, value: values.join(", "), screenshot: screenshot, metadata: { values: values } ) end |
#timeline ⇒ Object
Get the recording timeline for playback
186 187 188 |
# File 'app/services/action_agent/session_recording_service.rb', line 186 def timeline @recording.timeline end |
#type(selector:, text:, screenshot: nil, metadata: {}) ⇒ Object
Record a type/input action
57 58 59 60 61 62 63 64 65 |
# File 'app/services/action_agent/session_recording_service.rb', line 57 def type(selector:, text:, screenshot: nil, metadata: {}) record_action( action_type: "type", selector: selector, value: text, screenshot: screenshot, metadata: ) end |