Skip to main content
All parameter and response objects in the OpenAI Ruby SDK inherit from OpenAI::Internal::Type::BaseModel, which provides several conveniences for working with API data.

Core Features

BaseModel provides four main categories of functionality:

1. Flexible Field Access

All fields, including unknown or undocumented ones, are accessible with hash-style syntax:
completion = client.chat.completions.create(
  messages: [{role: "user", content: "Hello"}],
  model: "gpt-5.2"
)

# Access fields with hash syntax
content = completion[:choices][0][:message][:content]

# Or use method syntax
content = completion.choices[0].message.content

Pattern Matching

BaseModel objects support Ruby’s pattern matching syntax:
case completion
in { choices: [{ message: { content: content } }] }
  puts "Response: #{content}"
end

# Destructuring syntax
completion => { choices: choices }
puts "Got #{choices.size} choices"

2. Structural Equality

Two API responses are considered equal if they contain the same data:
response1 = client.chat.completions.create(
  messages: [{role: "user", content: "Say 'test'"}],
  model: "gpt-5.2",
  seed: 42
)

response2 = client.chat.completions.create(
  messages: [{role: "user", content: "Say 'test'"}],
  model: "gpt-5.2",
  seed: 42
)

# If responses have identical data, they are equal
if response1 == response2
  puts "Responses are structurally equivalent"
end
This is structural equality, not object identity. Two different API calls that return the same data will be considered equal.

3. Pretty Printing

Both instances and classes can be pretty-printed for debugging:
# Pretty-print an instance
pp completion

# Output:
# #<OpenAI::Chat::ChatCompletion
#  id="chatcmpl-123",
#  object="chat.completion",
#  created=1677652288,
#  model="gpt-5.2-0125",
#  choices=
#   [#<OpenAI::Chat::ChatCompletion::Choice
#     index=0,
#     message=
#      #<OpenAI::Chat::ChatCompletionMessage
#       role="assistant",
#       content="Hello! How can I help you today?">,
#     finish_reason="stop">],
#  usage=
#   #<OpenAI::CompletionUsage
#    prompt_tokens=9,
#    completion_tokens=9,
#    total_tokens=18>>
Pretty-printing classes shows their structure:
pp OpenAI::Chat::CompletionCreateParams
# Shows all available parameters and their types

4. Serialization Helpers

BaseModel provides multiple serialization methods:
# Shallow hash conversion
hash = completion.to_h
# => { id: "chatcmpl-123", object: "chat.completion", ... }

# Nested objects remain as BaseModel instances
hash[:choices][0].class
# => OpenAI::Chat::ChatCompletion::Choice

Accessing Undocumented Fields

BaseModel’s hash access syntax lets you read undocumented or future API fields:
completion = client.chat.completions.create(
  messages: [{role: "user", content: "Hello"}],
  model: "gpt-5.2"
)

# Access a field that might be added in the future
experimental_data = completion[:experimental_feature]

# Returns nil if the field doesn't exist
experimental_data.nil?
# => true (assuming the field doesn't exist)
This makes the SDK forward-compatible with API changes.

Usage Examples

Logging Responses

require 'logger'

logger = Logger.new(STDOUT)

completion = client.chat.completions.create(
  messages: [{role: "user", content: "What is Ruby?"}],
  model: "gpt-5.2"
)

# Log the full response as JSON
logger.info "API Response: #{completion.to_json}"

# Log specific fields
logger.info "Token usage: #{completion.usage.to_h}"

Caching Responses

require 'json'

# Save response to file
File.write('response.json', completion.to_json)

# Load and parse later
data = JSON.parse(File.read('response.json'))

# Access the cached data
puts data['choices'][0]['message']['content']

Testing with Structural Equality

require 'minitest/autorun'

class OpenAITest < Minitest::Test
  def test_deterministic_response
    response1 = client.chat.completions.create(
      messages: [{role: "user", content: "Count to 3"}],
      model: "gpt-5.2",
      seed: 42,
      temperature: 0
    )
    
    response2 = client.chat.completions.create(
      messages: [{role: "user", content: "Count to 3"}],
      model: "gpt-5.2",
      seed: 42,
      temperature: 0
    )
    
    # With the same seed and temperature=0, responses should match
    assert_equal response1, response2
  end
end

Implementation Details

The BaseModel implementation is in lib/openai/internal/type/base_model.rb in the gem source code.
BaseModel uses Ruby’s method_missing to provide both method-style (dot notation) and hash-style (bracket notation) access to fields. Method-style access is preferred for known fields, while hash-style access is useful for dynamic or unknown fields.

Sorbet Types

Sorbet type definitions and RBI files

RBS Types

RBS type signatures

Structured Outputs

BaseModel for structured outputs

Error Handling

Error response objects

Build docs developers (and LLMs) love