nightona 0.191.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +22 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE +190 -0
- data/README.md +184 -0
- data/Rakefile +12 -0
- data/lib/nightona/code_interpreter.rb +359 -0
- data/lib/nightona/common/charts.rb +124 -0
- data/lib/nightona/common/code_interpreter.rb +56 -0
- data/lib/nightona/common/code_language.rb +14 -0
- data/lib/nightona/common/file_system.rb +26 -0
- data/lib/nightona/common/git.rb +19 -0
- data/lib/nightona/common/image.rb +500 -0
- data/lib/nightona/common/nightona.rb +230 -0
- data/lib/nightona/common/process.rb +149 -0
- data/lib/nightona/common/pty.rb +309 -0
- data/lib/nightona/common/resources.rb +39 -0
- data/lib/nightona/common/response.rb +83 -0
- data/lib/nightona/common/snapshot.rb +124 -0
- data/lib/nightona/computer_use.rb +919 -0
- data/lib/nightona/config.rb +116 -0
- data/lib/nightona/file_system.rb +451 -0
- data/lib/nightona/file_transfer.rb +383 -0
- data/lib/nightona/git.rb +334 -0
- data/lib/nightona/lsp_server.rb +139 -0
- data/lib/nightona/nightona.rb +336 -0
- data/lib/nightona/object_storage.rb +172 -0
- data/lib/nightona/otel.rb +183 -0
- data/lib/nightona/process.rb +550 -0
- data/lib/nightona/sandbox.rb +751 -0
- data/lib/nightona/sdk/version.rb +10 -0
- data/lib/nightona/sdk.rb +56 -0
- data/lib/nightona/snapshot_service.rb +238 -0
- data/lib/nightona/util.rb +80 -0
- data/lib/nightona/volume.rb +46 -0
- data/lib/nightona/volume_service.rb +61 -0
- data/lib/nightona.rb +10 -0
- data/project.json +100 -0
- data/scripts/generate-docs.rb +402 -0
- data/sig/nightona/sdk.rbs +6 -0
- metadata +242 -0
|
@@ -0,0 +1,919 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module Nightona
|
|
7
|
+
class ComputerUse
|
|
8
|
+
class Mouse
|
|
9
|
+
include Instrumentation
|
|
10
|
+
|
|
11
|
+
# @return [String] The ID of the sandbox
|
|
12
|
+
attr_reader :sandbox_id
|
|
13
|
+
|
|
14
|
+
# @return [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
15
|
+
attr_reader :toolbox_api
|
|
16
|
+
|
|
17
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
18
|
+
# @param toolbox_api [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
19
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
20
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
21
|
+
@sandbox_id = sandbox_id
|
|
22
|
+
@toolbox_api = toolbox_api
|
|
23
|
+
@otel_state = otel_state
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Gets the current mouse cursor position.
|
|
27
|
+
#
|
|
28
|
+
# @return [NightonaToolboxApiClient::MousePosition] Current mouse position with x and y coordinates
|
|
29
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
# position = sandbox.computer_use.mouse.get_position
|
|
33
|
+
# puts "Mouse is at: #{position.x}, #{position.y}"
|
|
34
|
+
def position
|
|
35
|
+
toolbox_api.get_mouse_position
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
raise Sdk::Error, "Failed to get mouse position: #{e.message}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Moves the mouse cursor to the specified coordinates.
|
|
41
|
+
#
|
|
42
|
+
# @param x [Integer] The x coordinate to move to
|
|
43
|
+
# @param y [Integer] The y coordinate to move to
|
|
44
|
+
# @return [NightonaToolboxApiClient::MouseMoveResponse] Move operation result
|
|
45
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# result = sandbox.computer_use.mouse.move(x: 100, y: 200)
|
|
49
|
+
# puts "Mouse moved to: #{result.x}, #{result.y}"
|
|
50
|
+
def move(x:, y:)
|
|
51
|
+
request = NightonaToolboxApiClient::MouseMoveRequest.new(x:, y:)
|
|
52
|
+
toolbox_api.move_mouse(request)
|
|
53
|
+
rescue StandardError => e
|
|
54
|
+
raise Sdk::Error, "Failed to move mouse: #{e.message}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Clicks the mouse at the specified coordinates.
|
|
58
|
+
#
|
|
59
|
+
# @param x [Integer] The x coordinate to click at
|
|
60
|
+
# @param y [Integer] The y coordinate to click at
|
|
61
|
+
# @param button [String] The mouse button to click ('left', 'right', 'middle'). Defaults to 'left'
|
|
62
|
+
# @param double [Boolean] Whether to perform a double-click. Defaults to false
|
|
63
|
+
# @return [NightonaToolboxApiClient::MouseClickResponse] Click operation result
|
|
64
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
65
|
+
#
|
|
66
|
+
# @example
|
|
67
|
+
# # Single left click
|
|
68
|
+
# result = sandbox.computer_use.mouse.click(x: 100, y: 200)
|
|
69
|
+
#
|
|
70
|
+
# # Double click
|
|
71
|
+
# double_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'left', double: true)
|
|
72
|
+
#
|
|
73
|
+
# # Right click
|
|
74
|
+
# right_click = sandbox.computer_use.mouse.click(x: 100, y: 200, button: 'right')
|
|
75
|
+
def click(x:, y:, button: 'left', double: false)
|
|
76
|
+
request = NightonaToolboxApiClient::MouseClickRequest.new(x:, y:, button:, double:)
|
|
77
|
+
toolbox_api.click(request)
|
|
78
|
+
rescue StandardError => e
|
|
79
|
+
raise Sdk::Error, "Failed to click mouse: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Drags the mouse from start coordinates to end coordinates.
|
|
83
|
+
#
|
|
84
|
+
# @param start_x [Integer] The starting x coordinate
|
|
85
|
+
# @param start_y [Integer] The starting y coordinate
|
|
86
|
+
# @param end_x [Integer] The ending x coordinate
|
|
87
|
+
# @param end_y [Integer] The ending y coordinate
|
|
88
|
+
# @param button [String] The mouse button to use for dragging. Defaults to 'left'
|
|
89
|
+
# @return [NightonaToolboxApiClient::MouseDragResponse] Drag operation result
|
|
90
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
91
|
+
#
|
|
92
|
+
# @example
|
|
93
|
+
# result = sandbox.computer_use.mouse.drag(start_x: 50, start_y: 50, end_x: 150, end_y: 150)
|
|
94
|
+
# puts "Drag ended at #{result.x}, #{result.y}"
|
|
95
|
+
def drag(start_x:, start_y:, end_x:, end_y:, button: 'left')
|
|
96
|
+
request = NightonaToolboxApiClient::MouseDragRequest.new(start_x:, start_y:, end_x:, end_y:, button:)
|
|
97
|
+
toolbox_api.drag(request)
|
|
98
|
+
rescue StandardError => e
|
|
99
|
+
raise Sdk::Error, "Failed to drag mouse: #{e.message}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Scrolls the mouse wheel at the specified coordinates.
|
|
103
|
+
#
|
|
104
|
+
# @param x [Integer] The x coordinate to scroll at
|
|
105
|
+
# @param y [Integer] The y coordinate to scroll at
|
|
106
|
+
# @param direction [String] The direction to scroll ('up' or 'down')
|
|
107
|
+
# @param amount [Integer] The amount to scroll. Defaults to 1
|
|
108
|
+
# @return [Boolean] Whether the scroll operation was successful
|
|
109
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
110
|
+
#
|
|
111
|
+
# @example
|
|
112
|
+
# # Scroll up
|
|
113
|
+
# scroll_up = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'up', amount: 3)
|
|
114
|
+
#
|
|
115
|
+
# # Scroll down
|
|
116
|
+
# scroll_down = sandbox.computer_use.mouse.scroll(x: 100, y: 200, direction: 'down', amount: 5)
|
|
117
|
+
def scroll(x:, y:, direction:, amount: 1)
|
|
118
|
+
request = NightonaToolboxApiClient::MouseScrollRequest.new(x:, y:, direction:, amount:)
|
|
119
|
+
toolbox_api.scroll(request)
|
|
120
|
+
true
|
|
121
|
+
rescue StandardError => e
|
|
122
|
+
raise Sdk::Error, "Failed to scroll mouse: #{e.message}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
instrument :position, :move, :click, :drag, :scroll, component: 'Mouse'
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
# @return [Nightona::OtelState, nil]
|
|
130
|
+
attr_reader :otel_state
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Keyboard operations for computer use functionality.
|
|
134
|
+
class Keyboard
|
|
135
|
+
include Instrumentation
|
|
136
|
+
|
|
137
|
+
# @return [String] The ID of the sandbox
|
|
138
|
+
attr_reader :sandbox_id
|
|
139
|
+
|
|
140
|
+
# @return [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
141
|
+
attr_reader :toolbox_api
|
|
142
|
+
|
|
143
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
144
|
+
# @param toolbox_api [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
145
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
146
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
147
|
+
@sandbox_id = sandbox_id
|
|
148
|
+
@toolbox_api = toolbox_api
|
|
149
|
+
@otel_state = otel_state
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Types the specified text.
|
|
153
|
+
#
|
|
154
|
+
# @param text [String] The text to type
|
|
155
|
+
# @param delay [Integer, nil] Delay between characters in milliseconds
|
|
156
|
+
# @return [void]
|
|
157
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
158
|
+
#
|
|
159
|
+
# @example
|
|
160
|
+
# sandbox.computer_use.keyboard.type("Hello, World!")
|
|
161
|
+
#
|
|
162
|
+
# # With delay between characters
|
|
163
|
+
# sandbox.computer_use.keyboard.type("Slow typing", delay: 100)
|
|
164
|
+
def type(text:, delay: nil)
|
|
165
|
+
request = NightonaToolboxApiClient::KeyboardTypeRequest.new(text:, delay:)
|
|
166
|
+
toolbox_api.type_text(request)
|
|
167
|
+
rescue StandardError => e
|
|
168
|
+
raise Sdk::Error, "Failed to type text: #{e.message}"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Presses a key with optional modifiers.
|
|
172
|
+
#
|
|
173
|
+
# @param key [String] The key to press. Canonical names include 'enter', 'escape', 'tab', letters, digits, unshifted punctuation, function keys, and grammar-safe numpad names such as 'num_plus'. Named keys are case-insensitive, and common aliases such as 'Return' and 'Escape' are normalized.
|
|
174
|
+
# @param modifiers [Array<String>, nil] Canonical modifier names are 'ctrl', 'alt', 'shift', and 'cmd'. Common aliases such as 'control', 'option', 'meta', and 'win' are normalized.
|
|
175
|
+
# @return [void]
|
|
176
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
177
|
+
#
|
|
178
|
+
# @example
|
|
179
|
+
# # Press Enter
|
|
180
|
+
# sandbox.computer_use.keyboard.press("enter")
|
|
181
|
+
#
|
|
182
|
+
# # Press Ctrl+C
|
|
183
|
+
# sandbox.computer_use.keyboard.press("c", modifiers: ["ctrl"])
|
|
184
|
+
#
|
|
185
|
+
# # Press Ctrl+Shift+T
|
|
186
|
+
# sandbox.computer_use.keyboard.press("t", modifiers: ["ctrl", "shift"])
|
|
187
|
+
def press(key:, modifiers: nil)
|
|
188
|
+
request = NightonaToolboxApiClient::KeyboardPressRequest.new(key:, modifiers: modifiers || [])
|
|
189
|
+
toolbox_api.press_key(request)
|
|
190
|
+
rescue StandardError => e
|
|
191
|
+
raise Sdk::Error, "Failed to press key: #{e.message}"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Presses a hotkey combination.
|
|
195
|
+
#
|
|
196
|
+
# @param keys [String] A single atomic hotkey chord (e.g., 'ctrl+c', 'alt+tab', 'cmd+shift+t', 'ctrl + c', 'shift'). Uses the same normalized key contract as #press.
|
|
197
|
+
# @return [void]
|
|
198
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
199
|
+
#
|
|
200
|
+
# @example
|
|
201
|
+
# # Copy
|
|
202
|
+
# sandbox.computer_use.keyboard.hotkey("ctrl+c")
|
|
203
|
+
#
|
|
204
|
+
# # Paste
|
|
205
|
+
# sandbox.computer_use.keyboard.hotkey("ctrl+v")
|
|
206
|
+
#
|
|
207
|
+
# # Alt+Tab
|
|
208
|
+
# sandbox.computer_use.keyboard.hotkey("alt+tab")
|
|
209
|
+
def hotkey(keys:)
|
|
210
|
+
request = NightonaToolboxApiClient::KeyboardHotkeyRequest.new(keys:)
|
|
211
|
+
toolbox_api.press_hotkey(request)
|
|
212
|
+
rescue StandardError => e
|
|
213
|
+
raise Sdk::Error, "Failed to press hotkey: #{e.message}"
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
instrument :type, :press, :hotkey, component: 'Keyboard'
|
|
217
|
+
|
|
218
|
+
private
|
|
219
|
+
|
|
220
|
+
# @return [Nightona::OtelState, nil]
|
|
221
|
+
attr_reader :otel_state
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Screenshot operations for computer use functionality.
|
|
225
|
+
class Screenshot
|
|
226
|
+
include Instrumentation
|
|
227
|
+
|
|
228
|
+
# @return [String] The ID of the sandbox
|
|
229
|
+
attr_reader :sandbox_id
|
|
230
|
+
|
|
231
|
+
# @return [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
232
|
+
attr_reader :toolbox_api
|
|
233
|
+
|
|
234
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
235
|
+
# @param toolbox_api [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
236
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
237
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
238
|
+
@sandbox_id = sandbox_id
|
|
239
|
+
@toolbox_api = toolbox_api
|
|
240
|
+
@otel_state = otel_state
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Takes a screenshot of the entire screen.
|
|
244
|
+
#
|
|
245
|
+
# @param show_cursor [Boolean] Whether to show the cursor in the screenshot. Defaults to false
|
|
246
|
+
# @return [NightonaApiClient::ScreenshotResponse] Screenshot data with base64 encoded image
|
|
247
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
248
|
+
#
|
|
249
|
+
# @example
|
|
250
|
+
# screenshot = sandbox.computer_use.screenshot.take_full_screen
|
|
251
|
+
# puts "Screenshot size: #{screenshot.width}x#{screenshot.height}"
|
|
252
|
+
#
|
|
253
|
+
# # With cursor visible
|
|
254
|
+
# with_cursor = sandbox.computer_use.screenshot.take_full_screen(show_cursor: true)
|
|
255
|
+
def take_full_screen(show_cursor: false)
|
|
256
|
+
toolbox_api.take_screenshot(show_cursor:)
|
|
257
|
+
rescue StandardError => e
|
|
258
|
+
raise Sdk::Error, "Failed to take screenshot: #{e.message}"
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Takes a screenshot of a specific region.
|
|
262
|
+
#
|
|
263
|
+
# @param region [ScreenshotRegion] The region to capture
|
|
264
|
+
# @param show_cursor [Boolean] Whether to show the cursor in the screenshot. Defaults to false
|
|
265
|
+
# @return [NightonaApiClient::RegionScreenshotResponse] Screenshot data with base64 encoded image
|
|
266
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
267
|
+
#
|
|
268
|
+
# @example
|
|
269
|
+
# region = ScreenshotRegion.new(x: 100, y: 100, width: 300, height: 200)
|
|
270
|
+
# screenshot = sandbox.computer_use.screenshot.take_region(region)
|
|
271
|
+
# puts "Captured region: #{screenshot.region.width}x#{screenshot.region.height}"
|
|
272
|
+
def take_region(region:, show_cursor: false)
|
|
273
|
+
toolbox_api.take_region_screenshot(region.height, region.width, region.y, region.x, show_cursor:)
|
|
274
|
+
rescue StandardError => e
|
|
275
|
+
raise Sdk::Error, "Failed to take region screenshot: #{e.message}"
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Takes a compressed screenshot of the entire screen.
|
|
279
|
+
#
|
|
280
|
+
# @param options [ScreenshotOptions, nil] Compression and display options
|
|
281
|
+
# @return [NightonaApiClient::CompressedScreenshotResponse] Compressed screenshot data
|
|
282
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
283
|
+
#
|
|
284
|
+
# @example
|
|
285
|
+
# # Default compression
|
|
286
|
+
# screenshot = sandbox.computer_use.screenshot.take_compressed
|
|
287
|
+
#
|
|
288
|
+
# # High quality JPEG
|
|
289
|
+
# jpeg = sandbox.computer_use.screenshot.take_compressed(
|
|
290
|
+
# options: ScreenshotOptions.new(format: "jpeg", quality: 95, show_cursor: true)
|
|
291
|
+
# )
|
|
292
|
+
#
|
|
293
|
+
# # Scaled down PNG
|
|
294
|
+
# scaled = sandbox.computer_use.screenshot.take_compressed(
|
|
295
|
+
# options: ScreenshotOptions.new(format: "png", scale: 0.5)
|
|
296
|
+
# )
|
|
297
|
+
def take_compressed(options: nil)
|
|
298
|
+
options ||= ScreenshotOptions.new
|
|
299
|
+
toolbox_api.take_compressed_screenshot(
|
|
300
|
+
sandbox_id,
|
|
301
|
+
scale: options.scale,
|
|
302
|
+
quality: options.quality,
|
|
303
|
+
format: options.fmt,
|
|
304
|
+
show_cursor: options.show_cursor
|
|
305
|
+
)
|
|
306
|
+
rescue StandardError => e
|
|
307
|
+
raise Sdk::Error, "Failed to take compressed screenshot: #{e.message}"
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Takes a compressed screenshot of a specific region.
|
|
311
|
+
#
|
|
312
|
+
# @param region [ScreenshotRegion] The region to capture
|
|
313
|
+
# @param options [ScreenshotOptions, nil] Compression and display options
|
|
314
|
+
# @return [NightonaApiClient::CompressedScreenshotResponse] Compressed screenshot data
|
|
315
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
316
|
+
#
|
|
317
|
+
# @example
|
|
318
|
+
# region = ScreenshotRegion.new(x: 0, y: 0, width: 800, height: 600)
|
|
319
|
+
# screenshot = sandbox.computer_use.screenshot.take_compressed_region(
|
|
320
|
+
# region,
|
|
321
|
+
# options: ScreenshotOptions.new(format: "webp", quality: 80, show_cursor: true)
|
|
322
|
+
# )
|
|
323
|
+
# puts "Compressed size: #{screenshot.size_bytes} bytes"
|
|
324
|
+
def take_compressed_region(region:, options: nil)
|
|
325
|
+
options ||= ScreenshotOptions.new
|
|
326
|
+
toolbox_api.take_compressed_region_screenshot(
|
|
327
|
+
sandbox_id,
|
|
328
|
+
region.height,
|
|
329
|
+
region.width,
|
|
330
|
+
region.y,
|
|
331
|
+
region.x,
|
|
332
|
+
scale: options.scale,
|
|
333
|
+
quality: options.quality,
|
|
334
|
+
format: options.fmt,
|
|
335
|
+
show_cursor: options.show_cursor
|
|
336
|
+
)
|
|
337
|
+
rescue StandardError => e
|
|
338
|
+
raise Sdk::Error, "Failed to take compressed region screenshot: #{e.message}"
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
instrument :take_full_screen, :take_region, :take_compressed, :take_compressed_region,
|
|
342
|
+
component: 'Screenshot'
|
|
343
|
+
|
|
344
|
+
private
|
|
345
|
+
|
|
346
|
+
# @return [Nightona::OtelState, nil]
|
|
347
|
+
attr_reader :otel_state
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Display operations for computer use functionality.
|
|
351
|
+
class Display
|
|
352
|
+
include Instrumentation
|
|
353
|
+
|
|
354
|
+
# @return [String] The ID of the sandbox
|
|
355
|
+
attr_reader :sandbox_id
|
|
356
|
+
|
|
357
|
+
# @return [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
358
|
+
attr_reader :toolbox_api
|
|
359
|
+
|
|
360
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
361
|
+
# @param toolbox_api [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
362
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
363
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
364
|
+
@sandbox_id = sandbox_id
|
|
365
|
+
@toolbox_api = toolbox_api
|
|
366
|
+
@otel_state = otel_state
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Gets information about the displays.
|
|
370
|
+
#
|
|
371
|
+
# @return [NightonaToolboxApiClient::DisplayInfoResponse] Display information including primary display and all available displays
|
|
372
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
373
|
+
#
|
|
374
|
+
# @example
|
|
375
|
+
# info = sandbox.computer_use.display.get_info
|
|
376
|
+
# puts "Primary display: #{info.primary_display.width}x#{info.primary_display.height}"
|
|
377
|
+
# puts "Total displays: #{info.total_displays}"
|
|
378
|
+
# info.displays.each_with_index do |display, i|
|
|
379
|
+
# puts "Display #{i}: #{display.width}x#{display.height} at #{display.x},#{display.y}"
|
|
380
|
+
# end
|
|
381
|
+
def info
|
|
382
|
+
toolbox_api.get_display_info
|
|
383
|
+
rescue StandardError => e
|
|
384
|
+
raise Sdk::Error, "Failed to get display info: #{e.message}"
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Gets the list of open windows.
|
|
388
|
+
#
|
|
389
|
+
# @return [NightonaToolboxApiClient::WindowsResponse] List of open windows with their IDs and titles
|
|
390
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
391
|
+
#
|
|
392
|
+
# @example
|
|
393
|
+
# windows = sandbox.computer_use.display.get_windows
|
|
394
|
+
# puts "Found #{windows.count} open windows:"
|
|
395
|
+
# windows.windows.each do |window|
|
|
396
|
+
# puts "- #{window.title} (ID: #{window.id})"
|
|
397
|
+
# end
|
|
398
|
+
def windows
|
|
399
|
+
toolbox_api.get_windows
|
|
400
|
+
rescue StandardError => e
|
|
401
|
+
raise Sdk::Error, "Failed to get windows: #{e.message}"
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
instrument :info, :windows, component: 'Display'
|
|
405
|
+
|
|
406
|
+
private
|
|
407
|
+
|
|
408
|
+
# @return [Nightona::OtelState, nil]
|
|
409
|
+
attr_reader :otel_state
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
# Accessibility operations for computer use functionality.
|
|
413
|
+
class Accessibility
|
|
414
|
+
include Instrumentation
|
|
415
|
+
|
|
416
|
+
# @return [String] The ID of the sandbox
|
|
417
|
+
attr_reader :sandbox_id
|
|
418
|
+
|
|
419
|
+
# @return [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
420
|
+
attr_reader :toolbox_api
|
|
421
|
+
|
|
422
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
423
|
+
# @param toolbox_api [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
424
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
425
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
426
|
+
@sandbox_id = sandbox_id
|
|
427
|
+
@toolbox_api = toolbox_api
|
|
428
|
+
@otel_state = otel_state
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# Fetches the AT-SPI accessibility tree.
|
|
432
|
+
#
|
|
433
|
+
# @param scope [String, nil] Tree scope to inspect: "focused", "pid", or "all"
|
|
434
|
+
# @param pid [Integer, nil] Process ID when scope is "pid"
|
|
435
|
+
# @param max_depth [Integer, nil] Maximum depth to descend; 0 returns only the root
|
|
436
|
+
# @return [NightonaToolboxApiClient::AccessibilityTreeResponse] Accessibility tree response
|
|
437
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
438
|
+
#
|
|
439
|
+
# @example
|
|
440
|
+
# tree = sandbox.computer_use.accessibility.get_tree(scope: "all", max_depth: 3)
|
|
441
|
+
# puts tree.root.name
|
|
442
|
+
def get_tree(scope: nil, pid: nil, max_depth: nil)
|
|
443
|
+
opts = {}
|
|
444
|
+
opts[:scope] = scope unless scope.nil?
|
|
445
|
+
opts[:pid] = pid unless pid.nil?
|
|
446
|
+
opts[:max_depth] = max_depth unless max_depth.nil?
|
|
447
|
+
|
|
448
|
+
toolbox_api.get_accessibility_tree(opts)
|
|
449
|
+
rescue StandardError => e
|
|
450
|
+
raise Sdk::Error, "Failed to get accessibility tree: #{e.message}"
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Finds AT-SPI accessibility nodes matching the provided filters.
|
|
454
|
+
#
|
|
455
|
+
# @param scope [String, nil] Search scope: "focused", "pid", or "all"
|
|
456
|
+
# @param pid [Integer, nil] Process ID when scope is "pid"
|
|
457
|
+
# @param role [String, nil] Accessibility role to match, such as "button"
|
|
458
|
+
# @param name [String, nil] Accessible name to match
|
|
459
|
+
# @param name_match [String, nil] Name match mode, such as "exact" or "substring"
|
|
460
|
+
# @param states [Array<String>, nil] Required accessibility states
|
|
461
|
+
# @param limit [Integer, nil] Maximum number of matches
|
|
462
|
+
# @return [NightonaToolboxApiClient::AccessibilityNodesResponse] Matching accessibility nodes
|
|
463
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
464
|
+
#
|
|
465
|
+
# @example
|
|
466
|
+
# buttons = sandbox.computer_use.accessibility.find_nodes(
|
|
467
|
+
# scope: "all",
|
|
468
|
+
# role: "button",
|
|
469
|
+
# name: "Submit",
|
|
470
|
+
# name_match: "substring"
|
|
471
|
+
# )
|
|
472
|
+
# puts buttons.matches.length
|
|
473
|
+
def find_nodes(scope: nil, pid: nil, role: nil, name: nil, name_match: nil, states: nil, limit: nil)
|
|
474
|
+
attrs = {}
|
|
475
|
+
attrs[:scope] = scope unless scope.nil?
|
|
476
|
+
attrs[:pid] = pid unless pid.nil?
|
|
477
|
+
attrs[:role] = role unless role.nil?
|
|
478
|
+
attrs[:name] = name unless name.nil?
|
|
479
|
+
attrs[:name_match] = name_match unless name_match.nil?
|
|
480
|
+
attrs[:states] = states unless states.nil?
|
|
481
|
+
attrs[:limit] = limit unless limit.nil?
|
|
482
|
+
|
|
483
|
+
request = NightonaToolboxApiClient::FindAccessibilityNodesRequest.new(attrs)
|
|
484
|
+
toolbox_api.find_accessibility_nodes(request)
|
|
485
|
+
rescue StandardError => e
|
|
486
|
+
raise Sdk::Error, "Failed to find accessibility nodes: #{e.message}"
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
# Focuses an AT-SPI accessibility node.
|
|
490
|
+
#
|
|
491
|
+
# @param id [String] Accessibility node ID returned by get_tree or find_nodes
|
|
492
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
493
|
+
#
|
|
494
|
+
# @example
|
|
495
|
+
# sandbox.computer_use.accessibility.focus_node(id: node.id)
|
|
496
|
+
def focus_node(id:)
|
|
497
|
+
request = NightonaToolboxApiClient::AccessibilityNodeRequest.new(id:)
|
|
498
|
+
toolbox_api.focus_accessibility_node(request)
|
|
499
|
+
rescue StandardError => e
|
|
500
|
+
raise Sdk::Error, "Failed to focus accessibility node: #{e.message}"
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# Invokes an AT-SPI accessibility node action.
|
|
504
|
+
#
|
|
505
|
+
# @param id [String] Accessibility node ID returned by get_tree or find_nodes
|
|
506
|
+
# @param action [String, nil] Action name to invoke, or nil for the primary action
|
|
507
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
508
|
+
#
|
|
509
|
+
# @example
|
|
510
|
+
# sandbox.computer_use.accessibility.invoke_node(id: node.id, action: "click")
|
|
511
|
+
def invoke_node(id:, action: nil)
|
|
512
|
+
attrs = { id: }
|
|
513
|
+
attrs[:action] = action unless action.nil?
|
|
514
|
+
|
|
515
|
+
request = NightonaToolboxApiClient::AccessibilityInvokeRequest.new(attrs)
|
|
516
|
+
toolbox_api.invoke_accessibility_node(request)
|
|
517
|
+
rescue StandardError => e
|
|
518
|
+
raise Sdk::Error, "Failed to invoke accessibility node: #{e.message}"
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
# Sets an AT-SPI accessibility node value.
|
|
522
|
+
#
|
|
523
|
+
# @param id [String] Accessibility node ID returned by get_tree or find_nodes
|
|
524
|
+
# @param value [String] Value to write to the node
|
|
525
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
526
|
+
#
|
|
527
|
+
# @example
|
|
528
|
+
# sandbox.computer_use.accessibility.set_node_value(id: node.id, value: "hello")
|
|
529
|
+
def set_node_value(id:, value:)
|
|
530
|
+
request = NightonaToolboxApiClient::AccessibilitySetValueRequest.new(id:, value:)
|
|
531
|
+
toolbox_api.set_accessibility_node_value(request)
|
|
532
|
+
rescue StandardError => e
|
|
533
|
+
raise Sdk::Error, "Failed to set accessibility node value: #{e.message}"
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
instrument :get_tree, :find_nodes, :focus_node, :invoke_node, :set_node_value,
|
|
537
|
+
component: 'Accessibility'
|
|
538
|
+
|
|
539
|
+
private
|
|
540
|
+
|
|
541
|
+
# @return [Nightona::OtelState, nil]
|
|
542
|
+
attr_reader :otel_state
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
# Region coordinates for screenshot operations.
|
|
546
|
+
class ScreenshotRegion
|
|
547
|
+
# @return [Integer] X coordinate of the region
|
|
548
|
+
attr_accessor :x
|
|
549
|
+
|
|
550
|
+
# @return [Integer] Y coordinate of the region
|
|
551
|
+
attr_accessor :y
|
|
552
|
+
|
|
553
|
+
# @return [Integer] Width of the region
|
|
554
|
+
attr_accessor :width
|
|
555
|
+
|
|
556
|
+
# @return [Integer] Height of the region
|
|
557
|
+
attr_accessor :height
|
|
558
|
+
|
|
559
|
+
# @param x [Integer] X coordinate of the region
|
|
560
|
+
# @param y [Integer] Y coordinate of the region
|
|
561
|
+
# @param width [Integer] Width of the region
|
|
562
|
+
# @param height [Integer] Height of the region
|
|
563
|
+
def initialize(x:, y:, width:, height:)
|
|
564
|
+
@x = x
|
|
565
|
+
@y = y
|
|
566
|
+
@width = width
|
|
567
|
+
@height = height
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
# Options for screenshot compression and display.
|
|
572
|
+
class ScreenshotOptions
|
|
573
|
+
# @return [Boolean, nil] Whether to show the cursor in the screenshot
|
|
574
|
+
attr_accessor :show_cursor
|
|
575
|
+
|
|
576
|
+
# @return [String, nil] Image format (e.g., 'png', 'jpeg', 'webp')
|
|
577
|
+
attr_accessor :fmt
|
|
578
|
+
|
|
579
|
+
# @return [Integer, nil] Compression quality (0-100)
|
|
580
|
+
attr_accessor :quality
|
|
581
|
+
|
|
582
|
+
# @return [Float, nil] Scale factor for the screenshot
|
|
583
|
+
attr_accessor :scale
|
|
584
|
+
|
|
585
|
+
# @param show_cursor [Boolean, nil] Whether to show the cursor in the screenshot
|
|
586
|
+
# @param format [String, nil] Image format (e.g., 'png', 'jpeg', 'webp')
|
|
587
|
+
# @param quality [Integer, nil] Compression quality (0-100)
|
|
588
|
+
# @param scale [Float, nil] Scale factor for the screenshot
|
|
589
|
+
def initialize(show_cursor: nil, format: nil, quality: nil, scale: nil)
|
|
590
|
+
@show_cursor = show_cursor
|
|
591
|
+
@fmt = format
|
|
592
|
+
@quality = quality
|
|
593
|
+
@scale = scale
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
# Recording operations for computer use functionality.
|
|
598
|
+
class Recording
|
|
599
|
+
include Instrumentation
|
|
600
|
+
|
|
601
|
+
# @return [String] The ID of the sandbox
|
|
602
|
+
attr_reader :sandbox_id
|
|
603
|
+
|
|
604
|
+
# @return [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
605
|
+
attr_reader :toolbox_api
|
|
606
|
+
|
|
607
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
608
|
+
# @param toolbox_api [NightonaToolboxApiClient::ComputerUseApi] API client for sandbox operations
|
|
609
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
610
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
611
|
+
@sandbox_id = sandbox_id
|
|
612
|
+
@toolbox_api = toolbox_api
|
|
613
|
+
@otel_state = otel_state
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Starts a new screen recording session.
|
|
617
|
+
#
|
|
618
|
+
# @param label [String, nil] Optional custom label for the recording
|
|
619
|
+
# @return [NightonaToolboxApiClient::Recording] Started recording details
|
|
620
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
621
|
+
#
|
|
622
|
+
# @example
|
|
623
|
+
# # Start a recording with a label
|
|
624
|
+
# recording = sandbox.computer_use.recording.start(label: "my-test-recording")
|
|
625
|
+
# puts "Recording started: #{recording.id}"
|
|
626
|
+
# puts "File: #{recording.file_path}"
|
|
627
|
+
def start(label: nil)
|
|
628
|
+
request = NightonaToolboxApiClient::StartRecordingRequest.new(label:)
|
|
629
|
+
toolbox_api.start_recording(request: request)
|
|
630
|
+
rescue StandardError => e
|
|
631
|
+
raise Sdk::Error, "Failed to start recording: #{e.message}"
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
# Stops an active screen recording session.
|
|
635
|
+
#
|
|
636
|
+
# @param id [String] The ID of the recording to stop
|
|
637
|
+
# @return [NightonaToolboxApiClient::Recording] Stopped recording details
|
|
638
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
639
|
+
#
|
|
640
|
+
# @example
|
|
641
|
+
# result = sandbox.computer_use.recording.stop(id: recording.id)
|
|
642
|
+
# puts "Recording stopped: #{result.duration_seconds} seconds"
|
|
643
|
+
# puts "Saved to: #{result.file_path}"
|
|
644
|
+
def stop(id:)
|
|
645
|
+
request = NightonaToolboxApiClient::StopRecordingRequest.new(id: id)
|
|
646
|
+
toolbox_api.stop_recording(request)
|
|
647
|
+
rescue StandardError => e
|
|
648
|
+
raise Sdk::Error, "Failed to stop recording: #{e.message}"
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
# Lists all recordings (active and completed).
|
|
652
|
+
#
|
|
653
|
+
# @return [NightonaToolboxApiClient::ListRecordingsResponse] List of all recordings
|
|
654
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
655
|
+
#
|
|
656
|
+
# @example
|
|
657
|
+
# recordings = sandbox.computer_use.recording.list
|
|
658
|
+
# puts "Found #{recordings.recordings.length} recordings"
|
|
659
|
+
# recordings.recordings.each do |rec|
|
|
660
|
+
# puts "- #{rec.file_name}: #{rec.status}"
|
|
661
|
+
# end
|
|
662
|
+
def list
|
|
663
|
+
toolbox_api.list_recordings
|
|
664
|
+
rescue StandardError => e
|
|
665
|
+
raise Sdk::Error, "Failed to list recordings: #{e.message}"
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
# Gets details of a specific recording by ID.
|
|
669
|
+
#
|
|
670
|
+
# @param id [String] The ID of the recording to retrieve
|
|
671
|
+
# @return [NightonaToolboxApiClient::Recording] Recording details
|
|
672
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
673
|
+
#
|
|
674
|
+
# @example
|
|
675
|
+
# recording = sandbox.computer_use.recording.get(id: recording_id)
|
|
676
|
+
# puts "Recording: #{recording.file_name}"
|
|
677
|
+
# puts "Status: #{recording.status}"
|
|
678
|
+
# puts "Duration: #{recording.duration_seconds} seconds"
|
|
679
|
+
def get(id:)
|
|
680
|
+
toolbox_api.get_recording(id)
|
|
681
|
+
rescue StandardError => e
|
|
682
|
+
raise Sdk::Error, "Failed to get recording: #{e.message}"
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
# Deletes a recording by ID.
|
|
686
|
+
#
|
|
687
|
+
# @param id [String] The ID of the recording to delete
|
|
688
|
+
# @return [void]
|
|
689
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
690
|
+
#
|
|
691
|
+
# @example
|
|
692
|
+
# sandbox.computer_use.recording.delete(id: recording_id)
|
|
693
|
+
# puts "Recording deleted"
|
|
694
|
+
def delete(id:)
|
|
695
|
+
toolbox_api.delete_recording(id)
|
|
696
|
+
rescue StandardError => e
|
|
697
|
+
raise Sdk::Error, "Failed to delete recording: #{e.message}"
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
# Downloads a recording file and saves it to a local path.
|
|
701
|
+
#
|
|
702
|
+
# The file is streamed directly to disk without loading the entire content into memory.
|
|
703
|
+
#
|
|
704
|
+
# @param id [String] The ID of the recording to download
|
|
705
|
+
# @param local_path [String] Path to save the recording file locally
|
|
706
|
+
# @return [void]
|
|
707
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
708
|
+
#
|
|
709
|
+
# @example
|
|
710
|
+
# sandbox.computer_use.recording.download(id: recording_id, local_path: "local_recording.mp4")
|
|
711
|
+
# puts "Recording downloaded"
|
|
712
|
+
def download(id:, local_path:)
|
|
713
|
+
require 'fileutils'
|
|
714
|
+
require 'typhoeus'
|
|
715
|
+
|
|
716
|
+
# Get the API configuration and build the download URL
|
|
717
|
+
api_client = toolbox_api.api_client
|
|
718
|
+
config = api_client.config
|
|
719
|
+
base_url = config.base_url
|
|
720
|
+
download_url = "#{base_url}/computeruse/recordings/#{id}/download"
|
|
721
|
+
|
|
722
|
+
# Create parent directory if it doesn't exist
|
|
723
|
+
parent_dir = File.dirname(local_path)
|
|
724
|
+
FileUtils.mkdir_p(parent_dir) unless parent_dir.empty?
|
|
725
|
+
|
|
726
|
+
# Stream the download directly to file
|
|
727
|
+
file = File.open(local_path, 'wb')
|
|
728
|
+
request = Typhoeus::Request.new(
|
|
729
|
+
download_url,
|
|
730
|
+
method: :get,
|
|
731
|
+
headers: api_client.default_headers,
|
|
732
|
+
timeout: config.timeout,
|
|
733
|
+
ssl_verifypeer: config.verify_ssl,
|
|
734
|
+
ssl_verifyhost: config.verify_ssl_host ? 2 : 0
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
# Stream chunks directly to file
|
|
738
|
+
request.on_body do |chunk|
|
|
739
|
+
file.write(chunk)
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
request.on_complete do |response|
|
|
743
|
+
file.close
|
|
744
|
+
unless response.success?
|
|
745
|
+
File.delete(local_path) if File.exist?(local_path)
|
|
746
|
+
raise Sdk::Error, "Failed to download recording: HTTP #{response.code}"
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
|
|
750
|
+
request.run
|
|
751
|
+
rescue StandardError => e
|
|
752
|
+
file&.close
|
|
753
|
+
File.delete(local_path) if File.exist?(local_path)
|
|
754
|
+
raise Sdk::Error, "Failed to download recording: #{e.message}"
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
instrument :start, :stop, :list, :get, :delete, :download, component: 'Recording'
|
|
758
|
+
|
|
759
|
+
private
|
|
760
|
+
|
|
761
|
+
# @return [Nightona::OtelState, nil]
|
|
762
|
+
attr_reader :otel_state
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
include Instrumentation
|
|
766
|
+
|
|
767
|
+
# @return [String] The ID of the sandbox
|
|
768
|
+
attr_reader :sandbox_id
|
|
769
|
+
|
|
770
|
+
# @return [NightonaApiClient::ToolboxApi] API client for sandbox operations
|
|
771
|
+
attr_reader :toolbox_api
|
|
772
|
+
|
|
773
|
+
# @return [Mouse] Mouse operations interface
|
|
774
|
+
attr_reader :mouse
|
|
775
|
+
|
|
776
|
+
# @return [Keyboard] Keyboard operations interface
|
|
777
|
+
attr_reader :keyboard
|
|
778
|
+
|
|
779
|
+
# @return [Screenshot] Screenshot operations interface
|
|
780
|
+
attr_reader :screenshot
|
|
781
|
+
|
|
782
|
+
# @return [Display] Display operations interface
|
|
783
|
+
attr_reader :display
|
|
784
|
+
|
|
785
|
+
# @return [Recording] Screen recording operations interface
|
|
786
|
+
attr_reader :recording
|
|
787
|
+
|
|
788
|
+
# @return [Accessibility] Accessibility operations interface
|
|
789
|
+
attr_reader :accessibility
|
|
790
|
+
|
|
791
|
+
# Initialize a new ComputerUse instance.
|
|
792
|
+
#
|
|
793
|
+
# @param sandbox_id [String] The ID of the sandbox
|
|
794
|
+
# @param toolbox_api [NightonaApiClient::ToolboxApi] API client for sandbox operations
|
|
795
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
796
|
+
def initialize(sandbox_id:, toolbox_api:, otel_state: nil)
|
|
797
|
+
@sandbox_id = sandbox_id
|
|
798
|
+
@toolbox_api = toolbox_api
|
|
799
|
+
@otel_state = otel_state
|
|
800
|
+
@mouse = Mouse.new(sandbox_id:, toolbox_api:, otel_state:)
|
|
801
|
+
@keyboard = Keyboard.new(sandbox_id:, toolbox_api:, otel_state:)
|
|
802
|
+
@screenshot = Screenshot.new(sandbox_id:, toolbox_api:, otel_state:)
|
|
803
|
+
@display = Display.new(sandbox_id:, toolbox_api:, otel_state:)
|
|
804
|
+
@recording = Recording.new(sandbox_id:, toolbox_api:, otel_state:)
|
|
805
|
+
@accessibility = Accessibility.new(sandbox_id:, toolbox_api:, otel_state:)
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
# Starts all computer use processes (Xvfb, xfce4, x11vnc, novnc).
|
|
809
|
+
#
|
|
810
|
+
# @return [NightonaApiClient::ComputerUseStartResponse] Computer use start response
|
|
811
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
812
|
+
#
|
|
813
|
+
# @example
|
|
814
|
+
# result = sandbox.computer_use.start
|
|
815
|
+
# puts "Computer use processes started: #{result.message}"
|
|
816
|
+
def start
|
|
817
|
+
toolbox_api.start_computer_use
|
|
818
|
+
rescue StandardError => e
|
|
819
|
+
raise Sdk::Error, "Failed to start computer use: #{e.message}"
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
# Stops all computer use processes.
|
|
823
|
+
#
|
|
824
|
+
# @return [NightonaApiClient::ComputerUseStopResponse] Computer use stop response
|
|
825
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
826
|
+
#
|
|
827
|
+
# @example
|
|
828
|
+
# result = sandbox.computer_use.stop
|
|
829
|
+
# puts "Computer use processes stopped: #{result.message}"
|
|
830
|
+
def stop
|
|
831
|
+
toolbox_api.stop_computer_use
|
|
832
|
+
rescue StandardError => e
|
|
833
|
+
raise Sdk::Error, "Failed to stop computer use: #{e.message}"
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
# Gets the status of all computer use processes.
|
|
837
|
+
#
|
|
838
|
+
# @return [NightonaApiClient::ComputerUseStatusResponse] Status information about all VNC desktop processes
|
|
839
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
840
|
+
#
|
|
841
|
+
# @example
|
|
842
|
+
# response = sandbox.computer_use.get_status
|
|
843
|
+
# puts "Computer use status: #{response.status}"
|
|
844
|
+
def status
|
|
845
|
+
toolbox_api.get_computer_use_status
|
|
846
|
+
rescue StandardError => e
|
|
847
|
+
raise Sdk::Error, "Failed to get computer use status: #{e.message}"
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
# Gets the status of a specific VNC process.
|
|
851
|
+
#
|
|
852
|
+
# @param process_name [String] Name of the process to check
|
|
853
|
+
# @return [NightonaApiClient::ProcessStatusResponse] Status information about the specific process
|
|
854
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
855
|
+
#
|
|
856
|
+
# @example
|
|
857
|
+
# xvfb_status = sandbox.computer_use.get_process_status("xvfb")
|
|
858
|
+
# no_vnc_status = sandbox.computer_use.get_process_status("novnc")
|
|
859
|
+
def get_process_status(process_name:)
|
|
860
|
+
toolbox_api.get_process_status(process_name, sandbox_id)
|
|
861
|
+
rescue StandardError => e
|
|
862
|
+
raise Sdk::Error, "Failed to get process status: #{e.message}"
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
# Restarts a specific VNC process.
|
|
866
|
+
#
|
|
867
|
+
# @param process_name [String] Name of the process to restart
|
|
868
|
+
# @return [NightonaApiClient::ProcessRestartResponse] Process restart response
|
|
869
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
870
|
+
#
|
|
871
|
+
# @example
|
|
872
|
+
# result = sandbox.computer_use.restart_process("xfce4")
|
|
873
|
+
# puts "XFCE4 process restarted: #{result.message}"
|
|
874
|
+
def restart_process(process_name:)
|
|
875
|
+
toolbox_api.restart_process(process_name, sandbox_id)
|
|
876
|
+
rescue StandardError => e
|
|
877
|
+
raise Sdk::Error, "Failed to restart process: #{e.message}"
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
# Gets logs for a specific VNC process.
|
|
881
|
+
#
|
|
882
|
+
# @param process_name [String] Name of the process to get logs for
|
|
883
|
+
# @return [NightonaApiClient::ProcessLogsResponse] Process logs
|
|
884
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
885
|
+
#
|
|
886
|
+
# @example
|
|
887
|
+
# logs = sandbox.computer_use.get_process_logs("novnc")
|
|
888
|
+
# puts "NoVNC logs: #{logs}"
|
|
889
|
+
def get_process_logs(process_name:)
|
|
890
|
+
toolbox_api.get_process_logs(process_name, sandbox_id)
|
|
891
|
+
rescue StandardError => e
|
|
892
|
+
raise Sdk::Error, "Failed to get process logs: #{e.message}"
|
|
893
|
+
end
|
|
894
|
+
|
|
895
|
+
# Gets error logs for a specific VNC process.
|
|
896
|
+
#
|
|
897
|
+
# @param process_name [String] Name of the process to get error logs for
|
|
898
|
+
# @return [NightonaApiClient::ProcessErrorsResponse] Process error logs
|
|
899
|
+
# @raise [Nightona::Sdk::Error] If the operation fails
|
|
900
|
+
#
|
|
901
|
+
# @example
|
|
902
|
+
# errors = sandbox.computer_use.get_process_errors("x11vnc")
|
|
903
|
+
# puts "X11VNC errors: #{errors}"
|
|
904
|
+
def get_process_errors(process_name:)
|
|
905
|
+
toolbox_api.get_process_errors(process_name, sandbox_id)
|
|
906
|
+
rescue StandardError => e
|
|
907
|
+
raise Sdk::Error, "Failed to get process errors: #{e.message}"
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
instrument :start, :stop, :status, :get_process_status, :restart_process,
|
|
911
|
+
:get_process_logs, :get_process_errors,
|
|
912
|
+
component: 'ComputerUse'
|
|
913
|
+
|
|
914
|
+
private
|
|
915
|
+
|
|
916
|
+
# @return [Nightona::OtelState, nil]
|
|
917
|
+
attr_reader :otel_state
|
|
918
|
+
end
|
|
919
|
+
end
|