Class: LittleGhost::CodeMode::Javascript::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/little_ghost/code_mode/javascript/client.rb

Overview

:nodoc: all

Defined Under Namespace

Classes: Program

Constant Summary collapse

MAX_BUFFERED_OUTPUT_BYTES =
4 * 1024 * 1024
MAX_CAPTURED_STDERR_BYTES =
64 * 1024
SHUTDOWN_TIMEOUT =
0.5
TERMINATION_TIMEOUT =
1.0

Instance Method Summary collapse

Constructor Details

#initialize(session_factory:, framework_prompt_scope: {}) ⇒ Client

Returns a new instance of Client.



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 185

def initialize(session_factory:, framework_prompt_scope: {})
  unless session_factory.respond_to?(:call)
    raise ArgumentError, "Code-mode process-session factory must be callable"
  end
  @session_factory = session_factory
  @framework_prompt_scope = framework_prompt_scope.freeze

  @programs = {}
  @programs_mutex = Mutex.new
  @process_mutex = Mutex.new
  @writer_mutex = Mutex.new
  @closed = false
  @failure = nil
end

Instance Method Details

#closeObject



268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 268

def close
  process = @writer_mutex.synchronize do
    @process_mutex.synchronize do
      return if @closed

      @closed = true
      current = process_state
      clear_process_state
      current
    end
  end
  fail_all_programs(prompt("code_mode/feedback/closed", resource: "client"))
  stop_process(process)
end

#close_owner(owner) ⇒ Object



244
245
246
247
248
249
250
251
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 244

def close_owner(owner)
  programs = @programs_mutex.synchronize { @programs.values.select { |program| program.owner.equal?(owner) } }
  programs.each do |program|
    terminate(owner:, program_id: program.id)
  rescue LittleGhost::Error, IOError, SystemCallError
    release_program(program)
  end
end

#complete_tool_call(program_id:, call_id:, ok:, value: nil, error: nil) ⇒ Object



253
254
255
256
257
258
259
260
261
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 253

def complete_tool_call(program_id:, call_id:, ok:, value: nil, error: nil)
  program = @programs_mutex.synchronize { @programs[program_id.to_s] }
  return unless program

  send_message(
    {type: "tool_result", program_id:, call_id:, ok:, value:, error:},
    program:
  )
end

#fail_program(owner:, program_id:, error:) ⇒ Object



263
264
265
266
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 263

def fail_program(owner:, program_id:, error:)
  program = owned_program(owner, program_id)
  request_program_failure(program, error.message)
end

#observe(owner:, program_id:, timeout:, max_tokens:, context: nil) ⇒ Object



222
223
224
225
226
227
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 222

def observe(owner:, program_id:, timeout:, max_tokens:, context: nil)
  program = owned_program(owner, program_id)
  result = program.observe(timeout:, max_tokens:, context:)
  release_program(program) if program.terminal?
  result
end

#start_program(owner:, dispatcher:, source:, tools:, program_id: SecureRandom.uuid) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 200

def start_program(owner:, dispatcher:, source:, tools:, program_id: SecureRandom.uuid)
  program = nil
  send_message({type: "execute", program_id:, source:, tools:, messages: framework_messages}) do |generation|
    program = Program.new(
      id: program_id,
      owner:,
      dispatcher:,
      generation:,
      framework_prompt_scope: @framework_prompt_scope
    )
    @programs_mutex.synchronize do
      raise LittleGhost::ToolError, prompt("code_mode/feedback/closed", resource: "client") if @closed

      @programs[program.id] = program
    end
  end
  program.id
rescue
  @programs_mutex.synchronize { @programs.delete(program&.id) }
  raise
end

#terminate(owner:, program_id:, max_tokens: 10_000) ⇒ Object



229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/little_ghost/code_mode/javascript/client.rb', line 229

def terminate(owner:, program_id:, max_tokens: 10_000)
  program = owned_program(owner, program_id)
  send_message({type: "terminate", program_id: program.id}, program:) unless program.terminal?
  result = program.observe(timeout: TERMINATION_TIMEOUT, max_tokens:)
  unless program.terminal?
    process_failed(
      RuntimeError.new("Code-mode host did not acknowledge termination"),
      generation: program.generation
    )
    result = program.wait_until_terminal(timeout: TERMINATION_TIMEOUT + Javascript::Session::CLEANUP_TIMEOUT)
  end
  release_program(program)
  result
end