SpyBara
Go Premium

Reference 2026-08-10 22:00 UTC to 2026-08-11 22:59 UTC

1 file changed +137 −9. View all changes and history on the product overview
2026
Wed 12 16:01 Tue 11 22:59 Mon 10 22:00 Sat 8 00:59 Fri 7 21:59 Thu 6 18:59 Wed 5 02:01 Tue 4 22:59 Mon 3 21:58 Sat 1 01:00

ruby/index.md +137 −9

Details

82 82 

83Request parameters that correspond to file uploads can be passed as raw contents, a [`Pathname`](https://rubyapi.org/3.3/o/pathname) instance, [`StringIO`](https://rubyapi.org/3.3/o/stringio), or more.83Request parameters that correspond to file uploads can be passed as raw contents, a [`Pathname`](https://rubyapi.org/3.3/o/pathname) instance, [`StringIO`](https://rubyapi.org/3.3/o/stringio), or more.

84 84 

85Raw `String` and `StringIO` values, and `IO` objects without a path, do not carry format-identifying metadata. The SDK sends them using the fallback filename `upload`; raw `String` values default to `text/plain`, while `StringIO` and pathless `IO` values default to `application/octet-stream`. For format-sensitive endpoints, such as audio transcriptions, wrap each value in `OpenAI::FilePart` and provide an extension-bearing filename and content type.

86 

85```ruby87```ruby

86require "pathname"88require "pathname"

87 89 


93 95 

94puts(file_object.id)96puts(file_object.id)

95 97 

96# Or, to control the filename and/or content type:98# For format-sensitive uploads, provide the filename and content type:

97image = OpenAI::FilePart.new(Pathname('dog.jpg'), content_type: 'image/jpeg')99audio_data = StringIO.new(File.binread("audio.wav"))

100audio = OpenAI::FilePart.new(

101 audio_data,

102 filename: "audio.wav",

103 content_type: "audio/wav"

104)

105transcription = openai.audio.transcriptions.create(

106 model: "gpt-4o-transcribe",

107 file: audio

108)

109puts(transcription.text)

110 

111# FilePart also accepts a Pathname:

112image = OpenAI::FilePart.new(Pathname("dog.jpg"), content_type: "image/jpeg")

98edited = openai.images.edit(113edited = openai.images.edit(

99 prompt: "make this image look like a painting",114 prompt: "make this image look like a painting",

100 model: "gpt-image-1",115 model: "gpt-image-1",

101 size: '1024x1024',116 size: "1024x1024",

102 image: image117 image: image

103)118)

104 119 


608| Timeout | `APITimeoutError` |623| Timeout | `APITimeoutError` |

609| Network error | `APIConnectionError` |624| Network error | `APIConnectionError` |

610 625 

611### Request IDs626### Request logging

627 

628Request logging is disabled by default. Enable it with a standard Ruby logger

629when creating the client:

630 

631```ruby

632client = OpenAI::Client.new(

633 api_key: ENV.fetch("OPENAI_API_KEY"),

634 logger: Rails.logger,

635 log_level: :info

636)

637```

638 

639The logger can be any object that responds to `debug`, `info`, `warn`, and

640`error`; the SDK does not depend on Rails. Supplying a logger enables `:info`

641logging by default. When logging is enabled without a custom logger, the SDK

642uses a standard-library `Logger` that writes to stderr. Use `log_level: :off`

643when you only need retry notifications.

644 

645You can instead set `OPENAI_LOG=info` or `OPENAI_LOG=debug`. An explicit

646`log_level:` takes precedence over the environment variable.

647 

648For example, to use the stderr logger for one process:

649 

650```sh

651OPENAI_LOG=info bundle exec ruby app.rb

652```

653 

654A completion message includes the logical request and retry context:

655 

656```text

657[openai] request complete log_id=log_a1b2c3d4e5f6 method=POST path=/v1/responses status=200 request_id=req_123 attempts=1 duration_ms=42.7

658```

659 

660| Level | Behavior |

661| --- | --- |

662| `:off` | No SDK request logs (default) |

663| `:error` | Terminal request failures after retries are exhausted |

664| `:warn` | Error events plus retry reason and delay |

665| `:info` | Safe request completion summaries |

666| `:debug` | Per-attempt headers and bounded body diagnostics |

667 

668Info, warning, and error logs include operational fields such as the HTTP

669method, sanitized path, status, request ID, duration, and attempt count. They

670never include headers or bodies. Debug logs redact credential-bearing headers

671and query parameters, including authorization, API-key, cookie, token,

672credential, and signature values.

673 

674Debug logging can still disclose sensitive prompts, model responses, and tool

675arguments. Do not enable it in production unless your log destination and data

676retention policy are appropriate. The built-in logger omits uploaded file

677contents, multipart bodies, binary bodies, large opaque/base64-like values, and

678server-sent event contents. Text bodies are truncated to a fixed bound;

679oversized JSON and incomplete bodies are marked as omitted. Response bodies are

680observed only as the application consumes them and are never read eagerly for

681logging.

682 

683SDK log messages are intended for human diagnostics. Their text format is not

684a stable structured-event API and may change between releases. Exceptions from

685a supplied logger are isolated and never replace an API result or API error.

686 

687### Response metadata and request IDs

612 688 

613OpenAI recommends logging request IDs in production so requests can be traced689OpenAI recommends logging request IDs in production so requests can be traced

614during troubleshooting. Successful typed responses expose `_request_id`, which690during troubleshooting. Top-level models and pages returned by the client expose

615is populated from the `x-request-id` response header:691immutable HTTP response metadata through `last_response`:

616 692 

617```ruby693```ruby

618response = openai.responses.create(model: "gpt-5.2", input: "Say 'this is a test'.")694response = openai.responses.create(model: "gpt-5.2", input: "Say 'this is a test'.")

695puts(response.last_response.status) # 200

696puts(response.last_response.headers["x-request-id"]) # req_123

697puts(response.last_response.request_id) # req_123

619puts(response._request_id) # req_123698puts(response._request_id) # req_123

620```699```

621 700 

622The `_request_id` property is only populated on the top-level response object701Header names and values are normalized to strings, header names are lowercase,

623and is not included in `to_h`, JSON, or YAML output. Unlike other properties702and the metadata and header map are frozen. Streams expose the metadata for the

624that begin with an underscore, `_request_id` is public.703HTTP response that opened the stream. Higher-level streaming helpers expose the

704same metadata as their underlying stream; models assembled from stream events

705do not.

706 

707`last_response` and `_request_id` are only populated on top-level typed models

708and pages returned by the client. They are `nil` on constructed or nested models

709and are not included in `to_h`, JSON, or YAML output. Endpoints returning raw

710primitives, binary data, or `nil` do not expose this metadata. Unlike other

711properties that begin with an underscore, `_request_id` is public.

625 712 

626For failed HTTP requests, catch `OpenAI::Errors::APIStatusError` and use713For failed HTTP requests, catch `OpenAI::Errors::APIStatusError` and use

627`request_id`:714`request_id`:


660)747)

661```748```

662 749 

750To observe retries as they happen, supply an `on_retry` callback when creating

751the client. The callback runs immediately before the retry delay and receives

752an immutable `OpenAI::RetryEvent`:

753 

754```ruby

755openai = OpenAI::Client.new(

756 log_level: :off,

757 on_retry: lambda do |event|

758 Rails.logger.warn(

759 "OpenAI retry #{event.attempt}/#{event.max_attempts} " \

760 "status=#{event.status.inspect} request_id=#{event.request_id.inspect}"

761 )

762 end

763)

764```

765 

766For response-triggered retries, `event.response` contains the same immutable

767status, headers, and request ID shape as `last_response`. For connection errors,

768`event.error` is populated instead. Exceptions raised by the callback are

769isolated and do not replace the API result or error.

770 

663### Timeouts771### Timeouts

664 772 

665By default, requests will time out after 600 seconds. You can use the timeout option to configure or disable this:773By default, requests will time out after 600 seconds. You can use the timeout option to configure or disable this:


806openai.chat.completions.create(**params)914openai.chat.completions.create(**params)

807```915```

808 916 

917### Structured output models

918 

919The SDK includes a Tapioca DSL compiler for application-defined subclasses of

920`OpenAI::BaseModel`. When Tapioca loads your application, running

921`bundle exec tapioca dsl` generates typed readers for fields declared with

922`required`, including nested models, arrays, enums, unions, and fields declared

923with `nil?: true`.

924 

925Response `parsed` fields can contain different application-defined models, so

926their generated SDK type remains broad. Cast a parsed value to the structured

927output model supplied with the request before accessing its generated readers:

928 

929```ruby

930event = T.cast(content.parsed, CalendarEvent)

931puts(event.name)

932```

933 

934The compiler is only loaded by Tapioca; using the SDK normally still does not

935require `sorbet-runtime`.

936 

809### Enums937### Enums

810 938 

811Since this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:939Since this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime: