Class: TurnKit::Adapters::Codex

Inherits:
Client
  • Object
show all
Defined in:
lib/turnkit/adapters/codex.rb

Defined Under Namespace

Classes: Status

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command: ENV.fetch("CODEX_COMMAND", "codex"), sandbox: "read-only", working_directory: Dir.pwd, runner: nil) ⇒ Codex

Returns a new instance of Codex.



16
17
18
19
20
21
# File 'lib/turnkit/adapters/codex.rb', line 16

def initialize(command: ENV.fetch("CODEX_COMMAND", "codex"), sandbox: "read-only", working_directory: Dir.pwd, runner: nil)
  @command = command.to_s
  @sandbox = sandbox
  @working_directory = working_directory
  @runner = runner || method(:run_command)
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



14
15
16
# File 'lib/turnkit/adapters/codex.rb', line 14

def command
  @command
end

#sandboxObject (readonly)

Returns the value of attribute sandbox.



14
15
16
# File 'lib/turnkit/adapters/codex.rb', line 14

def sandbox
  @sandbox
end

#working_directoryObject (readonly)

Returns the value of attribute working_directory.



14
15
16
# File 'lib/turnkit/adapters/codex.rb', line 14

def working_directory
  @working_directory
end

Instance Method Details

#chat(model:, messages:, tools:, instructions:, temperature: nil, thinking: nil, output_schema: nil, metadata: nil, on_event: nil) ⇒ Object

Raises:



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/turnkit/adapters/codex.rb', line 35

def chat(model:, messages:, tools:, instructions:, temperature: nil, thinking: nil, output_schema: nil, metadata: nil, on_event: nil)
  raise ToolError, "TurnKit tools are not supported by the Codex adapter; Codex uses its own local tools" if Array(tools).any?

  with_tempfiles(output_schema: output_schema) do |schema_file, output_file|
    command = exec_command(model: model, schema_file: schema_file&.path, output_file: output_file.path)
    stdout, stderr, status = @runner.call(command, stdin_data: prompt_for(messages: messages, instructions: instructions), chdir: working_directory)
    emit_codex_events(stdout, on_event: on_event)
    raise ModelAccessError, stderr.strip.empty? ? "codex exec failed" : stderr.strip unless status.success?

    text = read_output(output_file, stdout)
    Result.new(
      text: text,
      output_data: parse_output_data(text, output_schema: output_schema),
      usage: usage_from_jsonl(stdout),
      model: model
    )
  end
end

#validate!(model:) ⇒ Object

Raises:



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/turnkit/adapters/codex.rb', line 23

def validate!(model:)
  raise ModelAccessError, "codex command is required" if command.empty?
  raise ModelAccessError, "#{command.inspect} was not found. Install OpenAI Codex CLI and run `codex login --device-auth`." unless executable?(command)

  stdout, stderr, status = @runner.call([ command, "login", "status" ], stdin_data: nil, chdir: working_directory)
  return true if status.success?

  message = [ stderr, stdout ].join("\n").strip
  hint = "Run `#{command} login --device-auth` to connect your ChatGPT/Codex subscription."
  raise ModelAccessError, [ "Codex is not authenticated.", message, hint ].reject(&:empty?).join(" ")
end