Class: Kreator::Providers::OpenAI

Inherits:
Base
  • Object
show all
Defined in:
lib/kreator/providers/openai.rb

Direct Known Subclasses

OpenRouter

Constant Summary collapse

DEFAULT_BASE_URL =
"https://api.openai.com/v1"
DEFAULT_CODEX_BASE_URL =
"https://chatgpt.com/backend-api"
CODEX_EVENT_HANDLERS =
{
  "response.output_text.delta" => :handle_codex_text_delta,
  "response.output_item.added" => :handle_codex_output_item_added,
  "response.function_call_arguments.delta" => :handle_codex_function_arguments_delta,
  "response.function_call_arguments.done" => :handle_codex_function_arguments_done,
  "response.output_item.done" => :handle_codex_output_item_done,
  "response.completed" => :handle_codex_response_completed,
  "response.done" => :handle_codex_response_completed,
  "response.failed" => :raise_codex_response_failed,
  "error" => :raise_codex_error
}.freeze

Constants inherited from Base

Base::DEFAULT_MAX_RETRIES, Base::TRANSIENT_HTTP_STATUSES

Instance Attribute Summary

Attributes inherited from Base

#api_key, #base_url, #max_retries, #name

Instance Method Summary collapse

Constructor Details

#initialize(api_key: nil, base_url: ENV.fetch("OPENAI_BASE_URL", DEFAULT_BASE_URL), name: "openai", max_retries: DEFAULT_MAX_RETRIES, auth: OpenAIAuth.resolve(api_key: api_key)) ⇒ OpenAI

Returns a new instance of OpenAI.

Raises:



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/kreator/providers/openai.rb', line 20

def initialize(
  api_key: nil,
  base_url: ENV.fetch("OPENAI_BASE_URL", DEFAULT_BASE_URL),
  name: "openai",
  max_retries: DEFAULT_MAX_RETRIES,
  auth: OpenAIAuth.resolve(api_key: api_key)
)
  raise Error, "OPENAI_API_KEY or OpenAI Codex/PI OAuth credentials are required for the openai provider" unless auth

  @auth = auth
  super(api_key: auth.token, base_url: base_url, name: name, max_retries: max_retries)
end

Instance Method Details

#capabilities(model) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/kreator/providers/openai.rb', line 56

def capabilities(model)
  context_window =
    case model.to_s
    when /gpt-5(?:\.|-|\z)/
      400_000
    when /4\.1/, /4o/
      128_000
    end

  super.merge(
    "vision" => model.to_s.match?(/gpt-5|4o|4\.1/),
    "reasoning" => model.to_s.match?(/gpt-5|o[134]|reasoning/),
    "context_window" => context_window
  )
end

#stream(messages:, tools:, system_prompt:, model:, signal:) {|type: "message_start", role: "assistant"| ... } ⇒ Object

Yields:

  • (type: "message_start", role: "assistant")


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/kreator/providers/openai.rb', line 33

def stream(messages:, tools:, system_prompt:, model:, signal:, &)
  return stream_codex_responses(messages: messages, tools: tools, system_prompt: system_prompt, model: model, signal: signal, &) if oauth_auth?

  yield type: "message_start", role: "assistant"

  body = openai_stream_body(messages, tools, system_prompt, model)
  stream_state = {
    tool_call_builders: {},
    emitted_model_output: false
  }

  begin
    stream_openai_events(body, signal, stream_state, &)

    tool_calls = stream_state.fetch(:tool_call_builders).values.map { |builder| build_tool_call(builder) }
    yield type: "message_end", tool_calls: tool_calls
  rescue Providers::Error
    raise if stream_state.fetch(:emitted_model_output)

    complete_once(body.merge(stream: false).except(:stream_options), &)
  end
end