Class: Daytona::Process

Inherits:
Object
  • Object
show all
Includes:
Instrumentation
Defined in:
lib/daytona/process.rb

Overview

rubocop:disable Metrics/ClassLength

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Instrumentation

included

Constructor Details

#initialize(sandbox_id:, toolbox_api:, get_preview_link:, language: 'python', otel_state: nil) ⇒ Process

Initialize a new Process instance

Parameters:

  • sandbox_id (String)

    The ID of the Sandbox

  • toolbox_api (DaytonaToolboxApiClient::ProcessApi)

    API client for Sandbox operations

  • get_preview_link (Proc)

    Function to get preview link for a port

  • language (String) (defaults to: 'python')

    The language for code execution

  • otel_state (Daytona::OtelState, nil) (defaults to: nil)


33
34
35
36
37
38
39
# File 'lib/daytona/process.rb', line 33

def initialize(sandbox_id:, toolbox_api:, get_preview_link:, language: 'python', otel_state: nil)
  @sandbox_id = sandbox_id
  @toolbox_api = toolbox_api
  @get_preview_link = get_preview_link
  @language = language
  @otel_state = otel_state
end

Instance Attribute Details

Returns Function to get preview link for a port.

Returns:

  • (Proc)

    Function to get preview link for a port



21
22
23
# File 'lib/daytona/process.rb', line 21

def get_preview_link
  @get_preview_link
end

#languageString (readonly)

Returns The language for code execution (e.g. 'python', 'typescript', 'javascript').

Returns:

  • (String)

    The language for code execution (e.g. 'python', 'typescript', 'javascript')



24
25
26
# File 'lib/daytona/process.rb', line 24

def language
  @language
end

#sandbox_idString (readonly)

Returns The ID of the Sandbox.

Returns:

  • (String)

    The ID of the Sandbox



15
16
17
# File 'lib/daytona/process.rb', line 15

def sandbox_id
  @sandbox_id
end

#toolbox_apiDaytonaToolboxApiClient::ProcessApi (readonly)

Returns API client for Sandbox operations.

Returns:

  • (DaytonaToolboxApiClient::ProcessApi)

    API client for Sandbox operations



18
19
20
# File 'lib/daytona/process.rb', line 18

def toolbox_api
  @toolbox_api
end

Instance Method Details

#code_run(code:, params: nil, timeout: nil) ⇒ ExecuteResponse

Execute code in the Sandbox using the appropriate language runtime

Examples:

# Run Python code
response = sandbox.process.code_run(<<~CODE)
  x = 10
  y = 20
  print(f"Sum: {x + y}")
CODE
puts response.artifacts.stdout  # Prints: Sum: 30

Parameters:

  • code (String)

    Code to execute

  • params (CodeRunParams, nil) (defaults to: nil)

    Parameters for code execution

  • timeout (Integer, nil) (defaults to: nil)

    Maximum time in seconds to wait for the code to complete. 0 means wait indefinitely

Returns:

  • (ExecuteResponse)

    Code execution result containing exit_code, result, and artifacts



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/daytona/process.rb', line 88

def code_run(code:, params: nil, timeout: nil)
  response = toolbox_api.code_run(
    DaytonaToolboxApiClient::CodeRunRequest.new(
      code:, language:, argv: params&.argv, envs: params&.env, timeout:
    )
  )

  ExecuteResponse.new(
    exit_code: response.exit_code,
    result: response.result,
    artifacts: ExecutionArtifacts.new(response.result, (response.artifacts&.charts || []).map do |c|
      Charts.parse_chart(c)
    end)
  )
end

#connect_pty_session(session_id) ⇒ PtyHandle

Connects to an existing PTY session in the Sandbox.

Establishes a WebSocket connection to an existing PTY session, allowing you to interact with a previously created terminal session.

Examples:

# Connect to an existing PTY session
pty_handle = sandbox.process.connect_pty_session("my-pty-session")
pty_handle.wait_for_connection
pty_handle.send_input("echo 'Hello World'\n")
result = pty_handle.wait
pty_handle.disconnect

Parameters:

  • session_id (String)

    Unique identifier of the PTY session to connect to.

Returns:

  • (PtyHandle)

    Handle for managing the connected PTY session.

Raises:



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/daytona/process.rb', line 460

def connect_pty_session(session_id) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  preview_link = get_preview_link.call(WS_PORT)
  url = URI.parse(preview_link.url)
  url.scheme = url.scheme == 'https' ? 'wss' : 'ws'
  url.path = "/process/pty/#{session_id}/connect"

  headers = toolbox_api.api_client.default_headers.dup.merge(
    'X-Daytona-Preview-Token' => preview_link.token
  )
  headers['Sec-WebSocket-Protocol'] =
    [headers['Sec-WebSocket-Protocol'], PTY_EXIT_CONTROL_SUBPROTOCOL].compact.join(', ')

  handle = nil
  WebSocket::Client::Simple.connect(url.to_s, headers:) do |client|
    handle = PtyHandle.new(
      client,
      session_id:,
      handle_resize: ->(pty_size) { resize_pty_session(session_id, pty_size) },
      handle_kill: -> { delete_pty_session(session_id) }
    )
  end
  handle.tap(&:wait_for_connection)
end

#create_pty_session(id:, cwd: nil, envs: nil, pty_size: nil) ⇒ PtyHandle

Creates a new PTY (pseudo-terminal) session in the Sandbox.

Creates an interactive terminal session that can execute commands and handle user input. The PTY session behaves like a real terminal, supporting features like command history.

Examples:

# Create a basic PTY session
pty_handle = sandbox.process.create_pty_session(id: "my-pty")

# Create a PTY session with specific size and environment
pty_size = Daytona::PtySize.new(rows: 30, cols: 120)
pty_handle = sandbox.process.create_pty_session(
  id: "my-pty",
  cwd: "/workspace",
  envs: {"NODE_ENV" => "development"},
  pty_size: pty_size
)

# Use the PTY session
pty_handle.wait_for_connection
pty_handle.send_input("ls -la\n")
result = pty_handle.wait
pty_handle.disconnect

Parameters:

  • id (String)

    Unique identifier for the PTY session. Must be unique within the Sandbox.

  • cwd (String, nil) (defaults to: nil)

    Working directory for the PTY session. Defaults to the sandbox's working directory.

  • envs (Hash<String, String>, nil) (defaults to: nil)

    Environment variables to set in the PTY session. These will be merged with the Sandbox's default environment variables.

  • pty_size (PtySize, nil) (defaults to: nil)

    Terminal size configuration. Defaults to 80x24 if not specified.

Returns:

  • (PtyHandle)

    Handle for managing the created PTY session. Use this to send input, receive output, resize the terminal, and manage the session lifecycle.

Raises:

  • (Daytona::Sdk::Error)

    If the PTY session creation fails or the session ID is already in use.



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
# File 'lib/daytona/process.rb', line 415

def create_pty_session(id:, cwd: nil, envs: nil, pty_size: nil) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
  cols = pty_size&.cols || 80
  rows = pty_size&.rows || 24

  preview_link = get_preview_link.call(WS_PORT)
  url = URI.parse(preview_link.url)
  url.scheme = url.scheme == 'https' ? 'wss' : 'ws'
  url.path = '/process/pty/create-connect'

  params = { id:, cols:, rows: }
  params[:cwd] = cwd if cwd
  url.query = URI.encode_www_form(params)

  headers = toolbox_api.api_client.default_headers.dup.merge(
    'X-Daytona-Preview-Token' => preview_link.token
  )
  protocols = [headers['Sec-WebSocket-Protocol'], PTY_EXIT_CONTROL_SUBPROTOCOL].compact
  protocols << "X-Daytona-Pty-Envs~#{Base64.urlsafe_encode64(envs.to_json, padding: false)}" if envs
  headers['Sec-WebSocket-Protocol'] = protocols.join(', ')

  PtyHandle.new(
    WebSocket::Client::Simple.connect(url.to_s, headers:),
    session_id: id,
    handle_resize: ->(pty_size_arg) { resize_pty_session(id, pty_size_arg) },
    handle_kill: -> { delete_pty_session(id) }
  ).tap(&:wait_for_connection)
end

#create_session(session_id) ⇒ void

This method returns an undefined value.

Creates a new long-running background session in the Sandbox

Sessions are background processes that maintain state between commands, making them ideal for scenarios requiring multiple related commands or persistent environment setup.

Examples:

# Create a new session
session_id = "my-session"
sandbox.process.create_session(session_id)
session = sandbox.process.get_session(session_id)
# Do work...
sandbox.process.delete_session(session_id)

Parameters:

  • session_id (String)

    Unique identifier for the new session



119
120
121
# File 'lib/daytona/process.rb', line 119

def create_session(session_id)
  toolbox_api.create_session(DaytonaToolboxApiClient::CreateSessionRequest.new(session_id:))
end

#delete_pty_session(session_id) ⇒ void

This method returns an undefined value.

Deletes a PTY session, terminating the associated process

Examples:

sandbox.process.delete_pty_session("my-pty")

Parameters:

  • session_id (String)

    Unique identifier of the PTY session to delete



511
512
513
# File 'lib/daytona/process.rb', line 511

def delete_pty_session(session_id)
  toolbox_api.delete_pty_session(session_id)
end

#delete_session(session_id) ⇒ Object

Terminates and removes a session from the Sandbox, cleaning up any resources associated with it

Examples:

# Create and use a session
sandbox.process.create_session("temp-session")
# ... use the session ...

# Clean up when done
sandbox.process.delete_session("temp-session")

Parameters:

  • session_id (String)

    Unique identifier of the session to delete



380
# File 'lib/daytona/process.rb', line 380

def delete_session(session_id) = toolbox_api.delete_session(session_id)

#exec(command:, cwd: nil, env: nil, timeout: nil) ⇒ ExecuteResponse

Execute a shell command in the Sandbox

Examples:

# Simple command
response = sandbox.process.exec("echo 'Hello'")
puts response.artifacts.stdout
=> "Hello\n"

# Command with working directory
result = sandbox.process.exec("ls", cwd: "workspace/src")

# Command with timeout
result = sandbox.process.exec("sleep 10", timeout: 5)

Parameters:

  • command (String)

    Shell command to execute

  • cwd (String, nil) (defaults to: nil)

    Working directory for command execution. If not specified, uses the sandbox working directory

  • env (Hash<String, String>, nil) (defaults to: nil)

    Environment variables to set for the command

  • timeout (Integer, nil) (defaults to: nil)

    Maximum time in seconds to wait for the command to complete.

Returns:

  • (ExecuteResponse)

    Command execution results containing exit_code, result, and artifacts



60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/daytona/process.rb', line 60

def exec(command:, cwd: nil, env: nil, timeout: nil)
  envs = env&.empty? ? nil : env

  response = toolbox_api.execute_command(DaytonaToolboxApiClient::ExecuteRequest.new(command:, cwd:, envs:,
                                                                                     timeout:))
  result = response.result || ''
  ExecuteResponse.new(
    exit_code: response.exit_code,
    result:,
    artifacts: ExecutionArtifacts.new(result, [])
  )
end

#execute_session_command(session_id:, req:) ⇒ Daytona::SessionExecuteResponse

Executes a command in the session

Examples:

# Execute commands in sequence, maintaining state
session_id = "my-session"

# Change directory
req = Daytona::SessionExecuteRequest.new(command: "cd /workspace")
sandbox.process.execute_session_command(session_id:, req:)

# Create a file
req = Daytona::SessionExecuteRequest.new(command: "echo 'Hello' > test.txt")
sandbox.process.execute_session_command(session_id:, req:)

# Read the file
req = Daytona::SessionExecuteRequest.new(command: "cat test.txt")
result = sandbox.process.execute_session_command(session_id:, req:)
puts "Command stdout: #{result.stdout}"
puts "Command stderr: #{result.stderr}"

Parameters:

  • session_id (String)

    Unique identifier of the session to use

  • req (Daytona::SessionExecuteRequest)

    Command execution request containing command and run_async

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/daytona/process.rb', line 184

def execute_session_command(session_id:, req:) # rubocop:disable Metrics/MethodLength
  response = toolbox_api.session_execute_command(
    session_id,
    DaytonaToolboxApiClient::SessionExecuteRequest.new(command: req.command, run_async: req.run_async,
                                                       suppress_input_echo: req.suppress_input_echo)
  )

  SessionExecuteResponse.new(
    cmd_id: response.cmd_id,
    output: response.output,
    stdout: response.stdout || '',
    stderr: response.stderr || '',
    exit_code: response.exit_code,
    additional_properties: {}
  )
end

#get_entrypoint_logsDaytona::SessionCommandLogsResponse

Get the sandbox entrypoint logs

Examples:

logs = sandbox.process.get_entrypoint_logs()
puts "Command stdout: #{logs.stdout}"
puts "Command stderr: #{logs.stderr}"

Returns:



282
283
284
285
# File 'lib/daytona/process.rb', line 282

def get_entrypoint_logs
  response = toolbox_api.get_entrypoint_logs
  SessionCommandLogsResponse.new(output: response.output, stdout: response.stdout, stderr: response.stderr)
end

#get_entrypoint_logs_async(on_stdout:, on_stderr:) ⇒ WebSocket::Client::Simple::Client

Asynchronously retrieves and processes the sandbox entrypoint logs as they become available

Examples:

sandbox.process.get_entrypoint_logs_async(
  on_stdout: ->(log) { puts "[STDOUT]: #{log}" },
  on_stderr: ->(log) { puts "[STDERR]: #{log}" }
)

Parameters:

  • on_stdout (Proc)

    Callback function to handle stdout log chunks as they arrive

  • on_stderr (Proc)

    Callback function to handle stderr log chunks as they arrive

Returns:

  • (WebSocket::Client::Simple::Client)


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/daytona/process.rb', line 298

def get_entrypoint_logs_async(on_stdout:, on_stderr:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  preview_link = get_preview_link.call(WS_PORT)
  url = URI.parse(preview_link.url)
  url.scheme = url.scheme == 'https' ? 'wss' : 'ws'
  url.path = '/process/session/entrypoint/logs'
  url.query = 'follow=true'

  completion_queue = Queue.new

  WebSocket::Client::Simple.connect(
    url.to_s,
    headers: toolbox_api.api_client.default_headers.dup.merge(
      'X-Daytona-Preview-Token' => preview_link.token,
      'Content-Type' => 'text/plain',
      'Accept' => 'text/plain'
    )
  ) do |client|
    client.on(:message) do |message|
      if message.type == :close
        client.close
        completion_queue.push(:close)
      else
        stdout, stderr = Util.demux(message.data.to_s)

        on_stdout.call(stdout) unless stdout.empty?
        on_stderr.call(stderr) unless stderr.empty?
      end
    end

    client.on(:close) do
      completion_queue.push(:close)
    end

    client.on(:error) do |e|
      completion_queue.push(:error)
      raise Sdk::Error, "WebSocket error: #{e.message}"
    end
  end

  # Wait for completion
  completion_queue.pop
end

#get_entrypoint_sessionDaytonaApiClient::Session

Gets the Sandbox entrypoint session

Examples:

session = sandbox.process.get_entrypoint_session()
session.commands.each do |cmd|
  puts "Command: #{cmd.command}"
end

Returns:

  • (DaytonaApiClient::Session)

    Entrypoint session information including session_id and commands



144
# File 'lib/daytona/process.rb', line 144

def get_entrypoint_session = toolbox_api.get_entrypoint_session

#get_pty_session_info(session_id) ⇒ DaytonaApiClient::PtySessionInfo

Gets detailed information about a specific PTY session

Retrieves comprehensive information about a PTY session including its current state, configuration, and metadata.

Examples:

# Get details about a specific PTY session
session_info = sandbox.process.get_pty_session_info("my-session")
puts "Session ID: #{session_info.id}"
puts "Active: #{session_info.active}"
puts "Working Directory: #{session_info.cwd}"
puts "Terminal Size: #{session_info.cols}x#{session_info.rows}"

Parameters:

  • session_id (String)

    Unique identifier of the PTY session to retrieve information for

Returns:

  • (DaytonaApiClient::PtySessionInfo)

    Detailed information about the PTY session including ID, state, creation time, working directory, environment variables, and more



547
548
549
# File 'lib/daytona/process.rb', line 547

def get_pty_session_info(session_id)
  toolbox_api.get_pty_session(session_id)
end

#get_session(session_id) ⇒ DaytonaApiClient::Session

Gets a session in the Sandbox

Examples:

session = sandbox.process.get_session("my-session")
session.commands.each do |cmd|
  puts "Command: #{cmd.command}"
end

Parameters:

  • session_id (String)

    Unique identifier of the session to retrieve

Returns:

  • (DaytonaApiClient::Session)

    Session information including session_id and commands



133
# File 'lib/daytona/process.rb', line 133

def get_session(session_id) = toolbox_api.get_session(session_id)

#get_session_command(session_id:, command_id:) ⇒ DaytonaApiClient::Command

Gets information about a specific command executed in a session

Examples:

cmd = sandbox.process.get_session_command(session_id: "my-session", command_id: "cmd-123")
if cmd.exit_code == 0
  puts "Command #{cmd.command} completed successfully"
end

Parameters:

  • session_id (String)

    Unique identifier of the session

  • command_id (String)

    Unique identifier of the command

Returns:

  • (DaytonaApiClient::Command)

    Command information including id, command, and exit_code



157
158
159
# File 'lib/daytona/process.rb', line 157

def get_session_command(session_id:, command_id:)
  toolbox_api.get_session_command(session_id, command_id)
end

#get_session_command_logs(session_id:, command_id:) ⇒ Daytona::SessionCommandLogsResponse

Get the logs for a command executed in a session

Examples:

logs = sandbox.process.get_session_command_logs(session_id: "my-session", command_id: "cmd-123")
puts "Command stdout: #{logs.stdout}"
puts "Command stderr: #{logs.stderr}"

Parameters:

  • session_id (String)

    Unique identifier of the session

  • command_id (String)

    Unique identifier of the command

Returns:



211
212
213
214
# File 'lib/daytona/process.rb', line 211

def get_session_command_logs(session_id:, command_id:)
  response = toolbox_api.get_session_command_logs(session_id, command_id)
  SessionCommandLogsResponse.new(output: response.output, stdout: response.stdout, stderr: response.stderr)
end

#get_session_command_logs_async(session_id:, command_id:, on_stdout:, on_stderr:) ⇒ WebSocket::Client::Simple::Client

Asynchronously retrieves and processes the logs for a command executed in a session as they become available

Examples:

sandbox.process.get_session_command_logs_async(
  session_id: "my-session",
  command_id: "cmd-123",
  on_stdout: ->(log) { puts "[STDOUT]: #{log}" },
  on_stderr: ->(log) { puts "[STDERR]: #{log}" }
)

Parameters:

  • session_id (String)

    Unique identifier of the session

  • command_id (String)

    Unique identifier of the command

  • on_stdout (Proc)

    Callback function to handle stdout log chunks as they arrive

  • on_stderr (Proc)

    Callback function to handle stderr log chunks as they arrive

Returns:

  • (WebSocket::Client::Simple::Client)


231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/daytona/process.rb', line 231

def get_session_command_logs_async(session_id:, command_id:, on_stdout:, on_stderr:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  preview_link = get_preview_link.call(WS_PORT)
  url = URI.parse(preview_link.url)
  url.scheme = url.scheme == 'https' ? 'wss' : 'ws'
  url.path = "/process/session/#{session_id}/command/#{command_id}/logs"
  url.query = 'follow=true'

  completion_queue = Queue.new

  WebSocket::Client::Simple.connect(
    url.to_s,
    headers: toolbox_api.api_client.default_headers.dup.merge(
      'X-Daytona-Preview-Token' => preview_link.token,
      'Content-Type' => 'text/plain',
      'Accept' => 'text/plain'
    )
  ) do |client|
    client.on(:message) do |message|
      if message.type == :close
        client.close
        completion_queue.push(:close)
      else
        stdout, stderr = Util.demux(message.data.to_s)

        on_stdout.call(stdout) unless stdout.empty?
        on_stderr.call(stderr) unless stderr.empty?
      end
    end

    client.on(:close) do
      completion_queue.push(:close)
    end

    client.on(:error) do |e|
      completion_queue.push(:error)
      raise Sdk::Error, "WebSocket error: #{e.message}"
    end
  end

  # Wait for completion
  completion_queue.pop
end

#list_pty_sessionsArray<DaytonaApiClient::PtySessionInfo>

Lists all PTY sessions in the Sandbox

Examples:

sessions = sandbox.process.list_pty_sessions
sessions.each do |session|
  puts "PTY Session #{session.id}: #{session.cols}x#{session.rows}"
end

Returns:

  • (Array<DaytonaApiClient::PtySessionInfo>)

    List of PTY session information



524
525
526
527
528
529
# File 'lib/daytona/process.rb', line 524

def list_pty_sessions
  response = toolbox_api.list_pty_sessions
  return [] if response.nil?

  response.respond_to?(:sessions) ? (response.sessions || []) : response
end

#list_sessionsArray<DaytonaApiClient::Session>

Returns List of all sessions in the Sandbox.

Examples:

sessions = sandbox.process.list_sessions
sessions.each do |session|
  puts "Session #{session.session_id}:"
  puts "  Commands: #{session.commands.length}"
end

Returns:

  • (Array<DaytonaApiClient::Session>)

    List of all sessions in the Sandbox



367
# File 'lib/daytona/process.rb', line 367

def list_sessions = toolbox_api.list_sessions

#resize_pty_session(session_id, pty_size) ⇒ DaytonaApiClient::PtySessionInfo

Resizes a PTY session to the specified dimensions

Examples:

pty_size = Daytona::PtySize.new(rows: 30, cols: 120)
session_info = sandbox.process.resize_pty_session("my-pty", pty_size)
puts "PTY resized to #{session_info.cols}x#{session_info.rows}"

Parameters:

  • session_id (String)

    Unique identifier of the PTY session

  • pty_size (PtySize)

    New terminal size

Returns:

  • (DaytonaApiClient::PtySessionInfo)

    Updated PTY session information



494
495
496
497
498
499
500
501
502
# File 'lib/daytona/process.rb', line 494

def resize_pty_session(session_id, pty_size)
  toolbox_api.resize_pty_session(
    session_id,
    DaytonaToolboxApiClient::PtyResizeRequest.new(
      cols: pty_size.cols,
      rows: pty_size.rows
    )
  )
end

#send_session_command_input(session_id:, command_id:, data:) ⇒ void

This method returns an undefined value.

Sends input data to a command executed in a session

This method allows you to send input to an interactive command running in a session, such as responding to prompts or providing data to stdin.

Parameters:

  • session_id (String)

    Unique identifier of the session

  • command_id (String)

    Unique identifier of the command

  • data (String)

    Input data to send to the command



350
351
352
353
354
355
356
# File 'lib/daytona/process.rb', line 350

def send_session_command_input(session_id:, command_id:, data:)
  toolbox_api.send_input(
    session_id,
    command_id,
    DaytonaToolboxApiClient::SessionSendInputRequest.new(data:)
  )
end