SpyBara
Go Premium

Documentation 2026-08-13 22:00 UTC to 2026-08-14 20:01 UTC

60 files changed +5,007 −26. View all changes and history on the product overview
2026
Sat 15 01:01 Fri 14 20:01 Thu 13 22:00 Wed 12 02:57 Tue 11 19:59 Mon 10 19:00 Fri 7 00:58 Thu 6 21:58 Wed 5 18:01 Tue 4 22:59 Mon 3 18:01
Details

51}51}

52```52```

53 53 

54```ruby

55require "openai"

56require "pathname"

57 

58client = OpenAI::Client.new

59file = Pathname("revenue-forecast.csv")

60uploaded = client.files.create(file: file, purpose: :assistants)

61puts(uploaded.id)

62```

63 

54```bash64```bash

55curl https://api.openai.com/v1/files \65curl https://api.openai.com/v1/files \

56 -H "Authorization: Bearer $OPENAI_API_KEY" \66 -H "Authorization: Bearer $OPENAI_API_KEY" \


101}111}

102```112```

103 113 

114```ruby

115require "openai"

116 

117client = OpenAI::Client.new

118assistant = client.beta.assistants.create(

119 name: "Data visualizer",

120 model: "gpt-4o",

121 instructions: "Analyze CSV data, create relevant visualizations, and summarize the trends.",

122 tools: [{type: :code_interpreter}],

123 tool_resources: {

124 code_interpreter: {file_ids: ["file-BK7bzQj3FfZFXr7DbL6xJwfo"]}

125 }

126)

127puts(assistant.id)

128```

129 

104```bash130```bash

105curl https://api.openai.com/v1/assistants \131curl https://api.openai.com/v1/assistants \

106 -H "Authorization: Bearer $OPENAI_API_KEY" \132 -H "Authorization: Bearer $OPENAI_API_KEY" \


179}205}

180```206```

181 207 

208```ruby

209require "openai"

210 

211client = OpenAI::Client.new

212thread = client.beta.threads.create(

213 messages: [{

214 role: :user,

215 content: "Create 3 data visualizations based on the trends in this file.",

216 attachments: [{

217 file_id: "file-ACq8OjcLQm2eIG0BvRM4z5qX",

218 tools: [{type: :code_interpreter}]

219 }]

220 }]

221)

222puts(thread.id)

223```

224 

182```bash225```bash

183curl https://api.openai.com/v1/threads \226curl https://api.openai.com/v1/threads \

184 -H "Authorization: Bearer $OPENAI_API_KEY" \227 -H "Authorization: Bearer $OPENAI_API_KEY" \


293}336}

294```337```

295 338 

339```ruby

340require "openai"

341require "pathname"

342 

343client = OpenAI::Client.new

344file = client.files.create(

345 file: Pathname("myimage.png"),

346 purpose: :vision

347)

348thread = client.beta.threads.create(

349 messages: [{

350 role: :user,

351 content: [

352 {type: :text, text: "What is the difference between these images?"},

353 {

354 type: :image_url,

355 image_url: {url: "https://openai-documentation.vercel.app/images/cat_and_otter.png"}

356 },

357 {type: :image_file, image_file: {file_id: file.id}}

358 ]

359 }]

360)

361puts(thread.id)

362```

363 

296```bash364```bash

297# Upload a file with an "vision" purpose365# Upload a file with an "vision" purpose

298curl https://api.openai.com/v1/files \366curl https://api.openai.com/v1/files \


398}466}

399```467```

400 468 

469```ruby

470require "openai"

471 

472client = OpenAI::Client.new

473thread = client.beta.threads.create(

474 messages: [{

475 role: :user,

476 content: [

477 {type: :text, text: "What is this an image of?"},

478 {

479 type: :image_url,

480 image_url: {

481 url: "https://openai-documentation.vercel.app/images/cat_and_otter.png",

482 detail: :high

483 }

484 }

485 ]

486 }]

487)

488puts(thread.id)

489```

490 

401```bash491```bash

402curl https://api.openai.com/v1/threads \492curl https://api.openai.com/v1/threads \

403 -H "Authorization: Bearer $OPENAI_API_KEY" \493 -H "Authorization: Bearer $OPENAI_API_KEY" \


557fmt.Println(messageContent.Value)647fmt.Println(messageContent.Value)

558```648```

559 649 

650```ruby

651require "openai"

652require "pathname"

653 

654client = OpenAI::Client.new

655message = client.beta.threads.messages.retrieve(

656 "msg_abc123",

657 thread_id: "thread_abc123"

658)

659text_block = message.content.find do |content|

660 content.is_a?(OpenAI::Models::Beta::Threads::TextContentBlock)

661end

662unless text_block.is_a?(OpenAI::Models::Beta::Threads::TextContentBlock)

663 raise "No text content returned"

664end

665text = text_block.text

666downloads = Pathname("downloads")

667references = text.annotations.each_with_index.filter_map do |annotation, index|

668 text.value = text.value.sub(annotation.text, " [#{index}]")

669 

670 case annotation

671 when OpenAI::Models::Beta::Threads::FileCitationAnnotation

672 file = client.files.retrieve(annotation.file_citation.file_id)

673 "[#{index}] #{file.filename}"

674 when OpenAI::Models::Beta::Threads::FilePathAnnotation

675 file_id = annotation.file_path.file_id

676 file = client.files.retrieve(file_id)

677 downloads.mkpath

678 output_path = downloads.join(Pathname(file.filename).basename)

679 output_path.binwrite(client.files.content(file_id).read)

680 "[#{index}] Downloaded #{output_path}"

681 end

682end

683 

684puts(([text.value] + references).join("\n"))

685```

686 

560 687 

561## Runs and Run Steps688## Runs and Run Steps

562 689 


584}711}

585```712```

586 713 

714```ruby

715require "openai"

716 

717client = OpenAI::Client.new

718run = client.beta.threads.runs.create("thread_abc123", assistant_id: "asst_ToSF7Gb04YMj8AMMm50ZLLtY")

719puts(run.id)

720```

721 

587```bash722```bash

588curl https://api.openai.com/v1/threads/THREAD_ID/runs \723curl https://api.openai.com/v1/threads/THREAD_ID/runs \

589 -H "Authorization: Bearer $OPENAI_API_KEY" \724 -H "Authorization: Bearer $OPENAI_API_KEY" \


631}766}

632```767```

633 768 

769```ruby

770require "openai"

771 

772client = OpenAI::Client.new

773run = client.beta.threads.runs.create(

774 "thread_abc123",

775 assistant_id: "asst_ToSF7Gb04YMj8AMMm50ZLLtY",

776 model: "gpt-4o",

777 instructions: "New instructions that override the Assistant instructions",

778 tools: [{type: :code_interpreter}, {type: :file_search}]

779)

780puts(run.id)

781```

782 

634```bash783```bash

635curl https://api.openai.com/v1/threads/THREAD_ID/runs \784curl https://api.openai.com/v1/threads/THREAD_ID/runs \

636 -H "Authorization: Bearer $OPENAI_API_KEY" \785 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

323conversation = openai.conversations.create(items=items)323conversation = openai.conversations.create(items=items)

324```324```

325 325 

326```ruby

327require "openai"

328 

329client = OpenAI::Client.new

330thread_id = ENV.fetch("OPENAI_THREAD_ID")

331messages = client.beta.threads.messages.list(thread_id, order: :asc)

332items = []

333messages.auto_paging_each do |message|

334 content = message.content.filter_map do |part|

335 case part

336 when OpenAI::Models::Beta::Threads::TextContentBlock

337 type = if message.role == OpenAI::Models::Beta::Threads::Message::Role::USER

338 :input_text

339 else

340 :output_text

341 end

342 {type: type, text: part.text.value}

343 when OpenAI::Models::Beta::Threads::ImageURLContentBlock

344 {

345 type: :input_image,

346 image_url: part.image_url.url,

347 detail: part.image_url.detail

348 }

349 end

350 end

351 items << {role: message.role, content: content}

352end

353conversation = client.conversations.create(

354 items: items

355)

356puts(conversation.id)

357```

358 

326 359 

327## Comparing full examples360## Comparing full examples

328 361 


371 return {"content": messages.data[0].content}404 return {"content": messages.data[0].content}

372```405```

373 406 

407```ruby

408require "openai"

409 

410client = OpenAI::Client.new

411assistant_id = ENV.fetch("OPENAI_ASSISTANT_ID")

412threads_by_session = {}

413 

414handle_message = lambda do |session_id:, content:|

415 thread_id = threads_by_session[session_id]

416 unless thread_id

417 thread_id = client.beta.threads.create.id

418 threads_by_session[session_id] = thread_id

419 end

420 

421 client.beta.threads.messages.create(

422 thread_id,

423 role: :user,

424 content: content

425 )

426 run = client.beta.threads.runs.create(

427 thread_id,

428 assistant_id: assistant_id

429 )

430 while [:queued, :in_progress].include?(run.status)

431 sleep(1)

432 run = client.beta.threads.runs.retrieve(run.id, thread_id: thread_id)

433 end

434 

435 messages = client.beta.threads.messages.list(

436 thread_id,

437 order: :desc,

438 limit: 1

439 )

440 {content: messages.data&.first&.content}

441end

442 

443puts(handle_message.call(

444 session_id: "example-session",

445 content: "What are the five Ds of dodgeball?"

446))

447```

448 

374 449 

375 450

376 451 


398 473 

399 return {"content": response.output_text}474 return {"content": response.output_text}

400```475```

476 

477```ruby

478require "openai"

479 

480client = OpenAI::Client.new

481conversations_by_session = {}

482 

483handle_message = lambda do |session_id:, content:|

484 conversation_id = conversations_by_session[session_id]

485 unless conversation_id

486 conversation_id = client.conversations.create.id

487 conversations_by_session[session_id] = conversation_id

488 end

489 

490 response = client.responses.create(

491 prompt: {id: ENV.fetch("OPENAI_PROMPT_ID")},

492 input: [{role: :user, content: content}],

493 conversation: conversation_id

494 )

495 {content: response.output_text}

496end

497 

498puts(handle_message.call(

499 session_id: "example-session",

500 content: "What are the five Ds of dodgeball?"

501))

502```

Details

46}46}

47```47```

48 48 

49```ruby

50require "openai"

51 

52client = OpenAI::Client.new

53assistant = client.beta.assistants.create(

54 model: "gpt-4o",

55 tools: [{type: :code_interpreter}]

56)

57puts(assistant.id)

58```

59 

49```bash60```bash

50curl https://api.openai.com/v1/assistants \61curl https://api.openai.com/v1/assistants \

51 -u :$OPENAI_API_KEY \62 -u :$OPENAI_API_KEY \


127}138}

128```139```

129 140 

141```ruby

142require "openai"

143require "pathname"

144 

145client = OpenAI::Client.new

146file = client.files.create(

147 file: Pathname("revenue-forecast.csv"),

148 purpose: :assistants

149)

150assistant = client.beta.assistants.create(

151 model: "gpt-4o",

152 instructions: "When asked a math question, write and run code to answer it.",

153 tools: [{type: :code_interpreter}],

154 tool_resources: {

155 code_interpreter: {file_ids: [file.id]}

156 }

157)

158puts(assistant.id)

159```

160 

130```bash161```bash

131# Upload a file with an "assistants" purpose162# Upload a file with an "assistants" purpose

132curl https://api.openai.com/v1/files \163curl https://api.openai.com/v1/files \


201}232}

202```233```

203 234 

235```ruby

236require "openai"

237 

238client = OpenAI::Client.new

239thread = client.beta.threads.create(

240 messages: [{

241 role: :user,

242 content: "I need to solve the equation `3x + 11 = 14`. Can you help me?",

243 attachments: [{

244 file_id: "file-ACq8OjcLQm2eIG0BvRM4z5qX",

245 tools: [{type: :code_interpreter}]

246 }]

247 }]

248)

249puts(thread.id)

250```

251 

204```bash252```bash

205curl https://api.openai.com/v1/threads/thread_abc123/messages \253curl https://api.openai.com/v1/threads/thread_abc123/messages \

206 -u :$OPENAI_API_KEY \254 -u :$OPENAI_API_KEY \


307}355}

308```356```

309 357 

358```ruby

359require "openai"

360 

361client = OpenAI::Client.new

362image = client.files.content("file-abc123")

363File.binwrite("my-image.png", image.read)

364```

365 

310```bash366```bash

311curl https://api.openai.com/v1/files/file-abc123/content \367curl https://api.openai.com/v1/files/file-abc123/content \

312 -H "Authorization: Bearer $OPENAI_API_KEY" \368 -H "Authorization: Bearer $OPENAI_API_KEY" \


371fmt.Println(runSteps.Data)427fmt.Println(runSteps.Data)

372```428```

373 429 

430```ruby

431require "openai"

432 

433client = OpenAI::Client.new

434steps = client.beta.threads.runs.steps.list(

435 "run_abc123",

436 thread_id: "thread_abc123"

437)

438puts(steps.data)

439```

440 

374```bash441```bash

375curl https://api.openai.com/v1/threads/thread_abc123/runs/RUN_ID/steps \442curl https://api.openai.com/v1/threads/thread_abc123/runs/RUN_ID/steps \

376 -H "Authorization: Bearer $OPENAI_API_KEY" \443 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

170}170}

171```171```

172 172 

173```ruby

174require "openai"

175 

176client = OpenAI::Client.new

177assistant = client.beta.assistants.create(

178 model: "gpt-4o",

179 instructions: "Use the provided functions to answer weather questions.",

180 tools: [

181 {

182 type: :function,

183 function: {

184 name: "get_current_temperature",

185 description: "Get the current temperature for a location",

186 parameters: {

187 type: :object,

188 properties: {

189 location: {type: :string},

190 unit: {type: :string, enum: ["Celsius", "Fahrenheit"]}

191 },

192 required: ["location", "unit"]

193 }

194 }

195 },

196 {

197 type: :function,

198 function: {

199 name: "get_rain_probability",

200 description: "Get the probability of rain for a location",

201 parameters: {

202 type: :object,

203 properties: {location: {type: :string}},

204 required: ["location"]

205 }

206 }

207 }

208 ]

209)

210puts(assistant.id)

211```

212 

173 213 

174### Step 2: Create a Thread and add Messages214### Step 2: Create a Thread and add Messages

175 215 


209}249}

210```250```

211 251 

252```ruby

253require "openai"

254 

255client = OpenAI::Client.new

256thread = client.beta.threads.create

257message = client.beta.threads.messages.create(

258 thread.id,

259 role: :user,

260 content: "What's the weather in San Francisco today, and will it rain?"

261)

262puts(message.id)

263```

264 

212 265 

213### Step 3: Initiate a Run266### Step 3: Initiate a Run

214 267 


556}609}

557```610```

558 611 

612```ruby

613require "openai"

614 

615client = OpenAI::Client.new

616thread_id = ENV.fetch("OPENAI_THREAD_ID")

617assistant_id = ENV.fetch("OPENAI_ASSISTANT_ID")

618 

619poll_run = lambda do |run|

620 while [

621 OpenAI::Beta::Threads::RunStatus::QUEUED,

622 OpenAI::Beta::Threads::RunStatus::IN_PROGRESS

623 ].include?(run.status)

624 sleep(2)

625 run = client.beta.threads.runs.retrieve(run.id, thread_id: thread_id)

626 end

627 run

628end

629 

630run = client.beta.threads.runs.create(thread_id, assistant_id: assistant_id)

631run = poll_run.call(run)

632 

633if run.status == OpenAI::Beta::Threads::RunStatus::REQUIRES_ACTION

634 required_action = run.required_action or raise "Run has no required action"

635 tool_outputs = required_action.submit_tool_outputs.tool_calls.filter_map do |tool_call|

636 output = case tool_call.function.name

637 when "get_current_temperature" then "57"

638 when "get_rain_probability" then "0.06"

639 end

640 {tool_call_id: tool_call.id, output: output} if output

641 end

642 raise "No supported tool calls were requested" if tool_outputs.empty?

643 

644 run = client.beta.threads.runs.submit_tool_outputs(

645 run.id,

646 thread_id: thread_id,

647 tool_outputs: tool_outputs

648 )

649 run = poll_run.call(run)

650end

651 

652if run.status == OpenAI::Beta::Threads::RunStatus::COMPLETED

653 messages = client.beta.threads.messages.list(thread_id)

654 messages.auto_paging_each { |message| puts(message.content) }

655else

656 warn("Run ended with status: #{run.status}")

657end

658```

659 

559 660 

560 661 

561### Using Structured Outputs662### Using Structured Outputs


730 }831 }

731}832}

732```833```

834 

835```ruby

836require "openai"

837 

838client = OpenAI::Client.new

839assistant = client.beta.assistants.create(

840 model: "gpt-4o",

841 name: "Weather assistant",

842 tools: [{type: :function, function: {name: "get_weather", description: "Get weather", parameters: {type: :object, properties: {city: {type: :string}}, required: ["city"], additionalProperties: false}, strict: true}}]

843)

844puts(assistant.id)

845```

Details

463```ruby463```ruby

464audit_logs = openai.admin.organization.audit_logs.list(limit: 10)464audit_logs = openai.admin.organization.audit_logs.list(limit: 10)

465 465 

466audit_logs.data.each do |audit_log|466(audit_logs.data || []).each do |audit_log|

467 puts(audit_log.id)467 puts(audit_log.id)

468end468end

469```469```

guides/audio.md +40 −0

Details

171}171}

172```172```

173 173 

174```ruby

175require "base64"

176require "openai"

177 

178client = OpenAI::Client.new

179completion = client.chat.completions.create(

180 model: "gpt-audio-1.5",

181 messages: [{role: :user, content: "Is a golden retriever a good family dog?"}],

182 modalities: [:text, :audio],

183 audio: {voice: :alloy, format: :wav},

184 store: true

185)

186 

187audio = completion.choices.fetch(0).message.audio or raise "No audio returned"

188File.binwrite("dog.wav", Base64.strict_decode64(audio.data))

189```

190 

174```bash191```bash

175curl "https://api.openai.com/v1/chat/completions" \192curl "https://api.openai.com/v1/chat/completions" \

176 -H "Content-Type: application/json" \193 -H "Content-Type: application/json" \


304}321}

305```322```

306 323 

324```ruby

325require "base64"

326require "openai"

327 

328client = OpenAI::Client.new

329audio = Base64.strict_encode64(File.binread("audio.wav"))

330completion = client.chat.completions.create(

331 model: "gpt-audio-1.5",

332 messages: [{

333 role: :user,

334 content: [

335 {type: :text, text: "What is in this recording?"},

336 {type: :input_audio, input_audio: {data: audio, format: :wav}}

337 ]

338 }],

339 modalities: [:text, :audio],

340 audio: {voice: :alloy, format: :wav},

341 store: true

342)

343 

344puts(completion.choices.fetch(0).message.content)

345```

346 

307```bash347```bash

308curl "https://api.openai.com/v1/chat/completions" \348curl "https://api.openai.com/v1/chat/completions" \

309 -H "Content-Type: application/json" \349 -H "Content-Type: application/json" \

Details

79}79}

80```80```

81 81 

82```ruby

83require "openai"

84 

85client = OpenAI::Client.new

86response = client.responses.create(

87 model: "gpt-5.6",

88 input: "Write a detailed market analysis.",

89 background: true

90)

91 

92puts(response.status)

93```

94 

82 95 

83## Polling background responses96## Polling background responses

84 97 


170}183}

171```184```

172 185 

186```ruby

187require "openai"

188 

189client = OpenAI::Client.new

190response = client.responses.create(

191 model: "gpt-5.6",

192 input: "Write a very long novel about otters in space.",

193 background: true

194)

195 

196while [:queued, :in_progress].include?(response.status)

197 puts("Current status: #{response.status}")

198 sleep(2)

199 response = client.responses.retrieve(response.id)

200end

201 

202puts("Final status: #{response.status}")

203puts(response.output_text)

204```

205 

173 206 

174## Cancelling a background response207## Cancelling a background response

175 208 


227}260}

228```261```

229 262 

263```ruby

264require "openai"

265 

266client = OpenAI::Client.new

267response = client.responses.cancel("resp_123")

268puts(response.status)

269```

270 

230 271 

231Cancelling twice is idempotent - subsequent calls simply return the final `Response` object.272Cancelling twice is idempotent - subsequent calls simply return the final `Response` object.

232 273 


351}392}

352```393```

353 394 

395```ruby

396require "openai"

397 

398client = OpenAI::Client.new

399stream = client.responses.stream(

400 model: "gpt-5.6",

401 input: "Write a very long novel about otters in space.",

402 background: true

403)

404 

405last_sequence_number = -1

406response_id = ""

407stream.each do |event|

408 puts(event.type)

409 last_sequence_number = event.sequence_number

410 if event.is_a?(OpenAI::Models::Responses::ResponseCreatedEvent)

411 response_id = event.response.id

412 end

413end

414 

415puts("Response #{response_id}; last sequence number #{last_sequence_number}")

416 

417# If the connection drops, resume from the last sequence number:

418# client.responses.stream(response_id: response_id, starting_after: last_sequence_number).each do |event|

419# puts(event.type)

420# end

421```

422 

354 423 

355## Limits424## Limits

356 425 

guides/batch.md +51 −0

Details

160}160}

161```161```

162 162 

163```ruby

164require "openai"

165require "pathname"

166 

167client = OpenAI::Client.new

168file = Pathname("batchinput.jsonl")

169uploaded = client.files.create(file: file, purpose: :batch)

170puts(uploaded.id)

171```

172 

163```bash173```bash

164curl https://api.openai.com/v1/files \174curl https://api.openai.com/v1/files \

165 -H "Authorization: Bearer $OPENAI_API_KEY" \175 -H "Authorization: Bearer $OPENAI_API_KEY" \


227}237}

228```238```

229 239 

240```ruby

241require "openai"

242 

243client = OpenAI::Client.new

244batch = client.batches.create(input_file_id: "file-abc123", endpoint: "/v1/responses", completion_window: "24h")

245puts(batch.id)

246```

247 

230```bash248```bash

231curl https://api.openai.com/v1/batches \249curl https://api.openai.com/v1/batches \

232 -H "Authorization: Bearer $OPENAI_API_KEY" \250 -H "Authorization: Bearer $OPENAI_API_KEY" \


313}331}

314```332```

315 333 

334```ruby

335require "openai"

336 

337client = OpenAI::Client.new

338batch = client.batches.retrieve("batch_abc123")

339puts(batch.status)

340```

341 

316```bash342```bash

317curl https://api.openai.com/v1/batches/batch_abc123 \343curl https://api.openai.com/v1/batches/batch_abc123 \

318 -H "Authorization: Bearer $OPENAI_API_KEY" \344 -H "Authorization: Bearer $OPENAI_API_KEY" \


392}418}

393```419```

394 420 

421```ruby

422require "openai"

423 

424client = OpenAI::Client.new

425content = client.files.content("file-xyz123")

426puts(content.read)

427```

428 

395```bash429```bash

396curl https://api.openai.com/v1/files/file-xyz123/content \430curl https://api.openai.com/v1/files/file-xyz123/content \

397 -H "Authorization: Bearer $OPENAI_API_KEY" > batch_output.jsonl431 -H "Authorization: Bearer $OPENAI_API_KEY" > batch_output.jsonl


465}499}

466```500```

467 501 

502```ruby

503require "openai"

504 

505client = OpenAI::Client.new

506batch = client.batches.cancel("batch_abc123")

507puts(batch.status)

508```

509 

468```bash510```bash

469curl https://api.openai.com/v1/batches/batch_abc123/cancel \511curl https://api.openai.com/v1/batches/batch_abc123/cancel \

470 -H "Authorization: Bearer $OPENAI_API_KEY" \512 -H "Authorization: Bearer $OPENAI_API_KEY" \


525}567}

526```568```

527 569 

570```ruby

571require "openai"

572 

573client = OpenAI::Client.new

574client.batches.list(limit: 10).auto_paging_each do |batch|

575 puts(batch.id)

576end

577```

578 

528```bash579```bash

529curl https://api.openai.com/v1/batches?limit=10 \580curl https://api.openai.com/v1/batches?limit=10 \

530 -H "Authorization: Bearer $OPENAI_API_KEY" \581 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

99}99}

100```100```

101 101 

102```ruby

103require "openai"

104 

105client = OpenAI::Client.new

106code = <<~PYTHON

107 def display_name(user):

108 return user.profile.name

109 

110 print(display_name(None))

111PYTHON

112 

113response = client.responses.create(

114 model: "gpt-5.6",

115 input: "Find the null pointer exception in this code:\n\n#{code}",

116 reasoning: {effort: :high}

117)

118 

119puts(response.output_text)

120```

121 

102```bash122```bash

103curl https://api.openai.com/v1/responses \123curl https://api.openai.com/v1/responses \

104 -H "Content-Type: application/json" \124 -H "Content-Type: application/json" \

Details

139}139}

140```140```

141 141 

142```ruby

143require "openai"

144 

145client = OpenAI::Client.new

146conversation = [{

147 type: :message,

148 role: :user,

149 content: "Let's begin a long coding task."

150}]

151 

152response = client.responses.create(

153 model: "gpt-5.3-codex",

154 input: conversation,

155 store: false,

156 context_management: [{type: :compaction, compact_threshold: 200_000}]

157)

158conversation.concat(response.output)

159conversation << {

160 type: :message,

161 role: :user,

162 content: "Now implement the next step."

163}

164next_response = client.responses.create(

165 model: "gpt-5.3-codex",

166 input: conversation,

167 store: false,

168 context_management: [{type: :compaction, compact_threshold: 200_000}]

169)

170puts(next_response.output_text)

171```

172 

142 173 

143## Standalone compact endpoint174## Standalone compact endpoint

144 175 


260 return input291 return input

261}292}

262```293```

294 

295```ruby

296require "openai"

297 

298client = OpenAI::Client.new

299long_input = [{role: :user, content: "Plan a trip to Kyoto."}]

300compaction = client.responses.compact(

301 model: "gpt-5.6",

302 input: long_input

303)

304next_input = [

305 *compaction.output,

306 {type: :message, role: :user, content: "Add restaurant recommendations."}

307]

308response = client.responses.create(

309 model: "gpt-5.6",

310 input: next_input,

311 store: false

312)

313puts(response.output_text)

314```

Details

46}46}

47```47```

48 48 

49```ruby

50require "openai"

51 

52client = OpenAI::Client.new

53completion = client.completions.create(model: "gpt-3.5-turbo-instruct", prompt: "Write a tagline for a bakery.", max_tokens: 24)

54puts(completion.choices.fetch(0).text)

55```

56 

49 57 

50See the full [API reference documentation](https://platform.openai.com/docs/api-reference/completions) to learn more.58See the full [API reference documentation](https://platform.openai.com/docs/api-reference/completions) to learn more.

51 59 

Details

85}85}

86```86```

87 87 

88```ruby

89require "openai"

90 

91client = OpenAI::Client.new

92 

93response = client.responses.create(

94 model: "gpt-5.6",

95 input: [

96 {role: :user, content: "Knock knock."},

97 {role: :assistant, content: "Who's there?"},

98 {role: :user, content: "Orange."}

99 ]

100)

101 

102puts(response.output_text)

103```

104 

88 105 

89 106 

90By using alternating `user` and `assistant` messages, you capture the previous state of a conversation in one request to the model.107By using alternating `user` and `assistant` messages, you capture the previous state of a conversation in one request to the model.


220}237}

221```238```

222 239 

240```ruby

241require "openai"

242 

243client = OpenAI::Client.new

244history = [{role: :user, content: "Tell me a joke."}]

245 

246first = client.responses.create(

247 model: "gpt-5.6",

248 input: history,

249 store: false

250)

251puts(first.output_text)

252 

253history.concat(first.output.map(&:to_h))

254history << {role: :user, content: "Tell me another."}

255 

256second = client.responses.create(

257 model: "gpt-5.6",

258 input: history,

259 store: false

260)

261puts(second.output_text)

262```

263 

223 264 

224 265 

225## OpenAI APIs for conversation state266## OpenAI APIs for conversation state


249}290}

250```291```

251 292 

293```ruby

294conversation = client.conversations.create

295```

296 

252 297 

253In a multi-turn interaction, you can pass the `conversation` into subsequent responses to persist state and share context across subsequent responses, rather than having to chain multiple response items together.298In a multi-turn interaction, you can pass the `conversation` into subsequent responses to persist state and share context across subsequent responses, rather than having to chain multiple response items together.

254 299 


278fmt.Println(response.OutputText())323fmt.Println(response.OutputText())

279```324```

280 325 

326```ruby

327response = client.responses.create(

328 model: "gpt-5.6",

329 conversation: conversation.id,

330 input: "What are the five Ds of dodgeball?"

331)

332 

333puts(response.output_text)

334```

335 

281 336 

282### Passing context from the previous response337### Passing context from the previous response

283 338 


366}421}

367```422```

368 423 

424```ruby

425require "openai"

426 

427client = OpenAI::Client.new

428 

429first = client.responses.create(

430 model: "gpt-5.6",

431 input: "Tell me a joke."

432)

433puts(first.output_text)

434 

435second = client.responses.create(

436 model: "gpt-5.6",

437 previous_response_id: first.id,

438 input: "Explain why this is funny."

439)

440puts(second.output_text)

441```

442 

369 443 

370In the following example, we ask the model to tell a joke. Separately, we ask the model to explain why it's funny, and the model has all necessary context to deliver a good response.444In the following example, we ask the model to tell a joke. Separately, we ask the model to explain why it's funny, and the model has all necessary context to deliver a good response.

371 445 


453}527}

454```528```

455 529 

530```ruby

531require "openai"

532 

533client = OpenAI::Client.new

534 

535first = client.responses.create(

536 model: "gpt-5.6",

537 input: "Tell me a joke."

538)

539puts(first.output_text)

540 

541second = client.responses.create(

542 model: "gpt-5.6",

543 previous_response_id: first.id,

544 input: "Explain why this is funny."

545)

546puts(second.output_text)

547```

548 

456 549 

457#### `previous_response_id` in WebSocket mode550#### `previous_response_id` in WebSocket mode

458 551 

Details

130}130}

131```131```

132 132 

133```ruby

134require "openai"

135 

136client = OpenAI::Client.new

137vector_store_id = ENV.fetch("OPENAI_VECTOR_STORE_ID")

138response = client.responses.create(

139 model: "o3-deep-research",

140 input: "Research the economic impact of semaglutide on global healthcare systems. Include measurable outcomes and cite primary sources.",

141 tools: [

142 {type: :web_search_preview},

143 {type: :file_search, vector_store_ids: [vector_store_id]},

144 {type: :code_interpreter, container: {type: :auto}}

145 ],

146 background: true

147)

148 

149while [

150 OpenAI::Responses::ResponseStatus::QUEUED,

151 OpenAI::Responses::ResponseStatus::IN_PROGRESS

152].include?(response.status)

153 sleep(2)

154 response = client.responses.retrieve(response.id)

155end

156unless response.status == OpenAI::Responses::ResponseStatus::COMPLETED

157 raise "Research ended with status: #{response.status}"

158end

159 

160puts(response.output_text)

161```

162 

133```bash163```bash

134curl https://api.openai.com/v1/responses \164curl https://api.openai.com/v1/responses \

135 -H "Authorization: Bearer $OPENAI_API_KEY" \165 -H "Authorization: Bearer $OPENAI_API_KEY" \


319}349}

320```350```

321 351 

352```ruby

353require "openai"

354 

355client = OpenAI::Client.new

356response = client.responses.create(

357 model: "gpt-5.6",

358 instructions: "Ask concise questions to gather all missing requirements. Do not conduct the research yet.",

359 input: "Research surfboards for me. I'm interested in ..."

360)

361 

362puts(response.output_text)

363```

364 

322```bash365```bash

323curl https://api.openai.com/v1/responses \366curl https://api.openai.com/v1/responses \

324-H "Authorization: Bearer $OPENAI_API_KEY" \367-H "Authorization: Bearer $OPENAI_API_KEY" \


587}630}

588```631```

589 632 

633```ruby

634require "openai"

635 

636client = OpenAI::Client.new

637response = client.responses.create(

638 model: "gpt-5.6",

639 instructions: "Rewrite the user's request as detailed research instructions. Preserve all stated preferences, identify open-ended dimensions, request primary sources, and specify a clear report format. Do not perform the research.",

640 input: "Research surfboards for me. I'm interested in ..."

641)

642 

643puts(response.output_text)

644```

645 

590```bash646```bash

591curl https://api.openai.com/v1/responses \647curl https://api.openai.com/v1/responses \

592 -H "Authorization: Bearer $OPENAI_API_KEY" \648 -H "Authorization: Bearer $OPENAI_API_KEY" \


741}797}

742```798```

743 799 

800```ruby

801require "openai"

802 

803client = OpenAI::Client.new

804mcp_server_url = ENV.fetch("OPENAI_MCP_SERVER_URL")

805response = client.responses.create(

806 model: "o3-deep-research",

807 input: "What patterns appear in our closed-lost Salesforce opportunities?",

808 instructions: "Produce a source-backed deep research report.",

809 reasoning: {summary: :auto},

810 tools: [{

811 type: :mcp,

812 server_label: "mycompany_mcp_server",

813 server_url: mcp_server_url,

814 require_approval: :never

815 }],

816 background: true

817)

818 

819while [

820 OpenAI::Responses::ResponseStatus::QUEUED,

821 OpenAI::Responses::ResponseStatus::IN_PROGRESS

822].include?(response.status)

823 sleep(2)

824 response = client.responses.retrieve(response.id)

825end

826unless response.status == OpenAI::Responses::ResponseStatus::COMPLETED

827 raise "Research ended with status: #{response.status}"

828end

829 

830puts(response.output_text)

831```

832 

744 833 

745[Build a deep research compatible remote MCP server834[Build a deep research compatible remote MCP server

746 835 

Details

150}150}

151```151```

152 152 

153```ruby

154require "openai"

155 

156client = OpenAI::Client.new

157prompt = <<~PROMPT

158 Our CI job started failing after a dependency bump.

159 

160 Error:

161 TypeError: Timeout.__init__() got an unexpected keyword argument 'connect'

162 

163 Identify the likeliest root cause and the smallest safe fix.

164PROMPT

165 

166response = client.responses.create(

167 model: "gpt-5.6",

168 reasoning: {effort: :xhigh, mode: :pro},

169 input: prompt

170)

171 

172puts(response.output_text)

173```

174 

153 175 

154## Set up `text.verbosity`176## Set up `text.verbosity`

155 177 


245}267}

246```268```

247 269 

270```ruby

271require "openai"

272 

273client = OpenAI::Client.new

274incident = <<~INCIDENT

275 Summarize this incident for the next on-call engineer.

276 - checkout latency spiked from 220 ms to 4.8 s

277 - only us-east-1 was affected

278 - rollback is complete

279 - likely trigger: cache stampede after deploy

280INCIDENT

281 

282response = client.responses.create(

283 model: "gpt-5.6",

284 text: {verbosity: :low},

285 input: incident

286)

287 

288puts(response.output_text)

289```

290 

248 291 

249## Set up the assistant `phase` parameter292## Set up the assistant `phase` parameter

250 293 


510}553}

511```554```

512 555 

556```ruby

557require "openai"

558 

559def namespace_tool(name, description, function_name, function_description, argument)

560 {

561 type: :namespace,

562 name: name,

563 description: description,

564 tools: [

565 {

566 type: :function,

567 name: function_name,

568 description: function_description,

569 defer_loading: true,

570 strict: true,

571 parameters: {

572 type: "object",

573 properties: {argument => {type: "string"}},

574 required: [argument],

575 additionalProperties: false

576 }

577 }

578 ]

579 }

580end

581 

582client = OpenAI::Client.new

583billing = namespace_tool(

584 "billing",

585 "Billing tools for invoices, payments, taxes, and credits.",

586 "lookup_invoice",

587 "Look up invoice state, taxes, credits, and payment attempts.",

588 "invoice_id"

589)

590crm = namespace_tool(

591 "crm",

592 "CRM tools for account ownership, plans, health, and payment history.",

593 "get_account",

594 "Fetch account owner, plan, health, and payment history.",

595 "account_id"

596)

597 

598response = client.responses.create(

599 model: "gpt-5.6",

600 input: "Find the right billing tool and explain why invoice INV-1043 still shows overdue after a payment yesterday.",

601 tools: [billing, crm, {type: :tool_search}]

602)

603 

604puts(response.output)

605```

606 

513 607 

514## Use Programmatic Tool Calling608## Use Programmatic Tool Calling

515 609 


740}834}

741```835```

742 836 

837```ruby

838require "openai"

839 

840client = OpenAI::Client.new

841long_window = [

842 {

843 role: :user,

844 content: "Find the cache invalidation bug in this debugging session."

845 }

846]

847 

848compacted = client.responses.compact(

849 model: "gpt-5.6",

850 input: long_window

851)

852input = compacted.output.map(&:to_h)

853input << {

854 role: :user,

855 content: "We found the bad cache invalidation path. Write the fix plan and the verification checklist."

856}

857 

858response = client.responses.create(

859 model: "gpt-5.6",

860 store: false,

861 input: input

862)

863 

864puts(response.output_text)

865```

866 

743 867 

744## Use `prompt_cache_key`868## Use `prompt_cache_key`

745 869 


846}970}

847```971```

848 972 

973```ruby

974require "openai"

975 

976client = OpenAI::Client.new

977instructions = <<~INSTRUCTIONS

978 You are the support agent for Acme.

979 Follow the Acme support policy and escalation rubric.

980 Use the same tone, safety rules, and tool plan for each ticket.

981INSTRUCTIONS

982 

983response = client.responses.create(

984 model: "gpt-5.6",

985 prompt_cache_key: "tenant-acme-support-agent",

986 instructions: instructions,

987 input: "Summarize the current escalation for the on-call lead."

988)

989 

990puts(response.output_text)

991```

992 

849 993 

850## Use `reasoning.encrypted_content`994## Use `reasoning.encrypted_content`

851 995 


1003}1147}

1004```1148```

1005 1149 

1150```ruby

1151require "openai"

1152 

1153client = OpenAI::Client.new

1154history = [

1155 {

1156 role: :user,

1157 content: "Investigate why invoice INV-1043 has mismatched tax totals."

1158 }

1159]

1160 

1161first = client.responses.create(

1162 model: "gpt-5.6",

1163 store: false,

1164 reasoning: {effort: :medium, context: :current_turn},

1165 include: ["reasoning.encrypted_content"],

1166 input: history

1167)

1168history.concat(first.output.map(&:to_h))

1169history << {

1170 role: :user,

1171 content: "Now write the customer-facing explanation in plain English."

1172}

1173 

1174second = client.responses.create(

1175 model: "gpt-5.6",

1176 store: false,

1177 reasoning: {effort: :medium, context: :all_turns},

1178 input: history

1179)

1180 

1181puts(second.output_text)

1182```

1183 

1006 1184 

1007## Set image detail intentionally1185## Set image detail intentionally

1008 1186 


1136}1314}

1137```1315```

1138 1316 

1317```ruby

1318require "openai"

1319 

1320client = OpenAI::Client.new

1321 

1322job = client.responses.create(

1323 model: "gpt-5.6",

1324 background: true,

1325 store: false,

1326 input: "Analyze this large log bundle and cluster the primary failure modes.",

1327 tools: [

1328 {

1329 type: :code_interpreter,

1330 container: {type: :auto, file_ids: ["file_abc123"]}

1331 }

1332 ]

1333)

1334 

1335while [:queued, :in_progress].include?(job.status)

1336 sleep(2)

1337 job = client.responses.retrieve(job.id)

1338end

1339 

1340puts(job.output_text)

1341```

1342 

1139 1343 

1140You can combine it with `stream=True` for progress events, but the first event1344You can combine it with `stream=True` for progress events, but the first event

1141may take longer than a normal request.1345may take longer than a normal request.

Details

160}160}

161```161```

162 162 

163```ruby

164require "openai"

165 

166client = OpenAI::Client.new

167job = client.fine_tuning.jobs.create(

168 model: "gpt-4.1-mini-2025-04-14",

169 training_file: "file-all-about-the-weather",

170 method_: {

171 type: :dpo,

172 dpo: {hyperparameters: {beta: 0.1}}

173 }

174)

175puts(job.id)

176```

177 

163 178 

164## Use SFT and DPO together179## Use SFT and DPO together

165 180 

Details

75}75}

76```76```

77 77 

78```ruby

79require "openai"

80 

81client = OpenAI::Client.new

82 

83response = client.embeddings.create(

84 model: "text-embedding-3-small",

85 input: "The food was delicious and the waiter..."

86)

87 

88puts(response.data.fetch(0).embedding)

89```

90 

78```bash91```bash

79curl https://api.openai.com/v1/embeddings \92curl https://api.openai.com/v1/embeddings \

80 -H "Content-Type: application/json" \93 -H "Content-Type: application/json" \

Details

290 fmt.Println(response.OutputText())290 fmt.Println(response.OutputText())

291}291}

292```292```

293 

294```ruby

295require "openai"

296 

297client = OpenAI::Client.new

298begin

299 response = client.responses.create(model: "gpt-5.6", input: "Say hello.")

300 puts(response.output_text)

301rescue OpenAI::Errors::APIError => error

302 warn(error.message)

303end

304```

guides/evals.md +75 −0

Details

109}109}

110```110```

111 111 

112```ruby

113require "openai"

114 

115client = OpenAI::Client.new

116instructions = <<~INSTRUCTIONS

117 You are an expert in categorizing IT support tickets. Given the support

118 ticket below, categorize the request as Hardware, Software, or Other.

119 Respond with only one of those words.

120INSTRUCTIONS

121response = client.responses.create(

122 model: "gpt-5.6",

123 input: [

124 {role: :developer, content: instructions},

125 {role: :user, content: "My monitor won't turn on - help!"}

126 ]

127)

128puts(response.output_text)

129```

130 

112```bash131```bash

113curl https://api.openai.com/v1/responses \132curl https://api.openai.com/v1/responses \

114 -H "Authorization: Bearer $OPENAI_API_KEY" \133 -H "Authorization: Bearer $OPENAI_API_KEY" \


204print(eval_obj)223print(eval_obj)

205```224```

206 225 

226```ruby

227require "openai"

228 

229client = OpenAI::Client.new

230evaluation = client.evals.create(

231 name: "Support answer quality",

232 data_source_config: {type: :custom, item_schema: {type: :object, properties: {input: {type: :string}}, required: ["input"]}},

233 testing_criteria: [{type: :string_check, name: "mentions_refund", input: "{{sample.output_text}}", operation: :contains, reference: "refund"}]

234)

235puts(evaluation.id)

236```

237 

207```bash238```bash

208curl https://api.openai.com/v1/evals \239curl https://api.openai.com/v1/evals \

209 -H "Authorization: Bearer $OPENAI_API_KEY" \240 -H "Authorization: Bearer $OPENAI_API_KEY" \


379}410}

380```411```

381 412 

413```ruby

414require "openai"

415require "pathname"

416 

417client = OpenAI::Client.new

418file = Pathname("tickets.jsonl")

419uploaded = client.files.create(file: file, purpose: :evals)

420puts(uploaded.id)

421```

422 

382```bash423```bash

383curl https://api.openai.com/v1/files \424curl https://api.openai.com/v1/files \

384 -H "Authorization: Bearer $OPENAI_API_KEY" \425 -H "Authorization: Bearer $OPENAI_API_KEY" \


467print(run)508print(run)

468```509```

469 510 

511```ruby

512require "openai"

513 

514client = OpenAI::Client.new

515run = client.evals.runs.create(

516 "YOUR_EVAL_ID",

517 name: "Categorization text run",

518 data_source: {

519 type: :responses,

520 source: {type: :file_id, id: "YOUR_FILE_ID"},

521 input_messages: {

522 type: :template,

523 template: [

524 {

525 role: :developer,

526 content: "Categorize the ticket as Hardware, Software, or Other."

527 },

528 {role: :user, content: "{{ item.ticket_text }}"}

529 ]

530 },

531 model: "gpt-5.6"

532 }

533)

534puts(run.id)

535```

536 

470```bash537```bash

471curl https://api.openai.com/v1/evals/YOUR_EVAL_ID/runs \538curl https://api.openai.com/v1/evals/YOUR_EVAL_ID/runs \

472 -H "Authorization: Bearer $OPENAI_API_KEY" \539 -H "Authorization: Bearer $OPENAI_API_KEY" \


576print(run)643print(run)

577```644```

578 645 

646```ruby

647require "openai"

648 

649client = OpenAI::Client.new

650run = client.evals.runs.retrieve("YOUR_RUN_ID", eval_id: "YOUR_EVAL_ID")

651puts(run.id)

652```

653 

579```bash654```bash

580curl https://api.openai.com/v1/evals/YOUR_EVAL_ID/runs/YOUR_RUN_ID \655curl https://api.openai.com/v1/evals/YOUR_EVAL_ID/runs/YOUR_RUN_ID \

581 -H "Authorization: Bearer $OPENAI_API_KEY" \656 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

69}69}

70```70```

71 71 

72```ruby

73require "openai"

74 

75client = OpenAI::Client.new

76 

77response = client.responses.create(

78 model: "gpt-5.6-sol",

79 service_tier: :fast,

80 input: "What does 'fit check for my napalm era' mean?"

81)

82 

83puts(response.output_text)

84```

85 

72```bash86```bash

73curl https://api.openai.com/v1/responses \87curl https://api.openai.com/v1/responses \

74 -H "Authorization: Bearer $OPENAI_API_KEY" \88 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

433 433 

434```ruby434```ruby

435require "openai"435require "openai"

436require "pathname"

436 437 

437openai = OpenAI::Client.new438openai = OpenAI::Client.new

438 439 

439file = openai.files.create(440file = openai.files.create(

440 file: File.open("draconomicon.pdf", "rb"),441 file: Pathname("draconomicon.pdf"),

441 purpose: "user_data"442 purpose: "user_data"

442)443)

443 444 


615}616}

616```617```

617 618 

619```ruby

620require "base64"

621require "openai"

622 

623client = OpenAI::Client.new

624pdf_data = Base64.strict_encode64(File.binread("draconomicon.pdf"))

625response = client.responses.create(

626 model: "gpt-5.6",

627 input: [{

628 role: :user,

629 content: [

630 {

631 type: :input_file,

632 filename: "document.pdf",

633 file_data: "data:application/pdf;base64,#{pdf_data}"

634 },

635 {type: :input_text, text: "Summarize this document."}

636 ]

637 }]

638)

639 

640puts(response.output_text)

641```

642 

618```bash643```bash

619curl "https://api.openai.com/v1/responses" \644curl "https://api.openai.com/v1/responses" \

620 -H "Content-Type: application/json" \645 -H "Content-Type: application/json" \

Details

118}118}

119```119```

120 120 

121```ruby

122require "openai"

123 

124client = OpenAI::Client.new

125job = client.fine_tuning.jobs.create(

126 model: "gpt-4.1-mini-2025-04-14",

127 training_file: "file-abc123",

128 method_: {

129 type: :supervised,

130 supervised: {hyperparameters: {n_epochs: 2}}

131 }

132)

133puts(job.id)

134```

135 

121 136 

122## Adjust your dataset137## Adjust your dataset

123 138 

Details

82}82}

83```83```

84 84 

85```ruby

86require "openai"

87 

88client = OpenAI::Client.new(timeout: 900.0)

89 

90response = client.responses.create(

91 model: "gpt-5.6",

92 service_tier: :flex,

93 instructions: "List and describe all the metaphors used in this book.",

94 input: "<very long text of book here>"

95)

96 

97puts(response.output_text)

98```

99 

85```bash100```bash

86curl https://api.openai.com/v1/responses \101curl https://api.openai.com/v1/responses \

87 -H "Authorization: Bearer $OPENAI_API_KEY" \102 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

304}304}

305```305```

306 306 

307```ruby

308require "json"

309require "openai"

310 

311client = OpenAI::Client.new

312tools = [{

313 type: :function,

314 name: "get_horoscope",

315 description: "Get today's horoscope for an astrological sign.",

316 parameters: {

317 type: :object,

318 properties: {sign: {type: :string}},

319 required: ["sign"],

320 additionalProperties: false

321 },

322 strict: true

323}]

324 

325first_response = client.responses.create(

326 model: "gpt-5.6",

327 input: "What is my horoscope? I am an Aquarius.",

328 tools: tools

329)

330function_call = first_response.output.find do |item|

331 item.is_a?(OpenAI::Models::Responses::ResponseFunctionToolCall) &&

332 item.name == "get_horoscope"

333end

334unless function_call.is_a?(OpenAI::Models::Responses::ResponseFunctionToolCall)

335 raise "The model did not call get_horoscope"

336end

337 

338arguments = JSON.parse(function_call.arguments, symbolize_names: true)

339sign = arguments.fetch(:sign)

340response = client.responses.create(

341 model: "gpt-5.6",

342 previous_response_id: first_response.id,

343 input: [{

344 type: :function_call_output,

345 call_id: function_call.call_id,

346 output: "#{sign}: Embrace an unexpected opportunity today."

347 }],

348 tools: tools

349)

350 

351puts(response.output_text)

352```

353 

307 354 

308 355 

309Note that for reasoning models like GPT-5 or o4-mini, any reasoning items356Note that for reasoning models like GPT-5 or o4-mini, any reasoning items


531}578}

532```579```

533 580 

581```ruby

582input.concat(response.output)

583 

584response.output.each do |tool_call|

585 next unless tool_call.is_a?(OpenAI::Models::Responses::ResponseFunctionToolCall)

586 

587 arguments = JSON.parse(tool_call.arguments)

588 result = call_function(tool_call.name, arguments)

589 

590 input << {

591 type: :function_call_output,

592 call_id: tool_call.call_id,

593 output: JSON.generate(result)

594 }

595end

596```

597 

534 598 

535 599 

536In the example above, we have a hypothetical `call_function` to route each call. Here’s a possible implementation:600In the example above, we have a hypothetical `call_function` to route each call. Here’s a possible implementation:


571}635}

572```636```

573 637 

638```ruby

639def call_function(name, arguments)

640 case name

641 when "get_weather"

642 FunctionCallingExample.get_weather(

643 arguments.fetch("latitude"),

644 arguments.fetch("longitude")

645 )

646 when "send_email"

647 FunctionCallingExample.send_email(

648 arguments.fetch("to"),

649 arguments.fetch("body")

650 )

651 else

652 raise ArgumentError, "Unknown function: #{name}"

653 end

654end

655```

656 

574 657 

575### Formatting results658### Formatting results

576 659 


617}700}

618```701```

619 702 

703```ruby

704require "openai"

705 

706client = OpenAI::Client.new

707input = [

708 {role: :user, content: "What is the weather like in Paris?"},

709 {

710 type: :function_call,

711 call_id: "call_weather",

712 name: "get_weather",

713 arguments: '{"city":"Paris"}'

714 },

715 {

716 type: :function_call_output,

717 call_id: "call_weather",

718 output: '{"city":"Paris","temperature_c":18}'

719 }

720]

721tools = [{

722 type: :function,

723 name: "get_weather",

724 description: "Get the weather for a city",

725 parameters: {

726 type: :object,

727 properties: {city: {type: :string}},

728 required: ["city"],

729 additionalProperties: false

730 },

731 strict: true

732}]

733response = client.responses.create(

734 model: "gpt-5.6",

735 input: input,

736 tools: tools

737)

738 

739puts(response.output_text)

740```

741 

620 742 

621 743 

622Final response744Final response


899}1021}

900```1022```

901 1023 

1024```ruby

1025require "openai"

1026 

1027client = OpenAI::Client.new

1028stream = client.responses.stream(

1029 model: "gpt-5.6",

1030 input: "What is the weather in Paris?",

1031 tools: [{type: :function, name: "get_weather", description: "Get the weather for a city", parameters: {type: :object, properties: {city: {type: :string}}, required: ["city"], additionalProperties: false}, strict: true}]

1032)

1033 

1034stream.each { |event| puts(event.type) }

1035```

1036 

902 1037 

903Output events1038Output events

904 1039 


1023}1158}

1024```1159```

1025 1160 

1161```ruby

1162require "openai"

1163 

1164client = OpenAI::Client.new

1165stream = client.responses.stream(

1166 model: "gpt-5.6",

1167 input: "What is the weather in Paris?",

1168 tools: [{

1169 type: :function,

1170 name: "get_weather",

1171 parameters: {

1172 type: :object,

1173 properties: {location: {type: :string}},

1174 required: ["location"],

1175 additionalProperties: false

1176 },

1177 strict: true

1178 }]

1179)

1180 

1181final_tool_calls = {}

1182stream.each do |event|

1183 case event

1184 when OpenAI::Models::Responses::ResponseOutputItemAddedEvent

1185 item = event.item

1186 next unless item.is_a?(OpenAI::Models::Responses::ResponseFunctionToolCall)

1187 

1188 final_tool_calls[event.output_index] = {

1189 id: item.id,

1190 call_id: item.call_id,

1191 name: item.name,

1192 type: item.type,

1193 arguments: item.arguments.dup

1194 }

1195 when OpenAI::Models::Responses::ResponseFunctionCallArgumentsDeltaEvent

1196 tool_call = final_tool_calls[event.output_index]

1197 tool_call[:arguments] << event.delta if tool_call

1198 end

1199end

1200 

1201puts(final_tool_calls.sort.to_h.values)

1202```

1203 

1026 1204 

1027Accumulated final_tool_calls[0]1205Accumulated final_tool_calls[0]

1028 1206 


1121}1299}

1122```1300```

1123 1301 

1302```ruby

1303require "openai"

1304 

1305client = OpenAI::Client.new

1306response = client.responses.create(

1307 model: "gpt-5.6",

1308 input: "Use code_exec to print hello world.",

1309 tools: [{

1310 type: :custom,

1311 name: "code_exec",

1312 description: "Executes arbitrary Python code."

1313 }]

1314)

1315 

1316puts(response.output)

1317```

1318 

1124 1319 

1125Just as before, the `output` array will contain a tool call generated by the model. Except this time, the tool call input is given as plain text.1320Just as before, the `output` array will contain a tool call generated by the model. Except this time, the tool call input is given as plain text.

1126 1321 


1267}1462}

1268```1463```

1269 1464 

1465```ruby

1466require "openai"

1467 

1468client = OpenAI::Client.new

1469grammar = <<~LARK

1470 start: expr

1471 expr: term (SP ADD SP term)*

1472 term: INT

1473 SP: " "

1474 ADD: "+"

1475 %import common.INT

1476LARK

1477response = client.responses.create(

1478 model: "gpt-5.6",

1479 input: "Use math_exp to add four plus four.",

1480 tools: [{

1481 type: :custom,

1482 name: "math_exp",

1483 description: "Creates valid mathematical expressions.",

1484 format: {type: :grammar, syntax: :lark, definition: grammar}

1485 }]

1486)

1487 

1488puts(response.output)

1489```

1490 

1270 1491 

1271The output from the tool should then conform to the Lark CFG that you defined:1492The output from the tool should then conform to the Lark CFG that you defined:

1272 1493 


1463}1684}

1464```1685```

1465 1686 

1687```ruby

1688require "openai"

1689 

1690client = OpenAI::Client.new

1691grammar = "^(January|February|March|April|May|June|July|August|September|October|November|December) \\d{1,2}(st|nd|rd|th)? \\d{4} at (0?[1-9]|1[0-2])(AM|PM)$"

1692response = client.responses.create(

1693 model: "gpt-5.6",

1694 input: "Use timestamp to save August 7th 2025 at 10AM.",

1695 tools: [{

1696 type: :custom,

1697 name: "timestamp",

1698 description: "Saves a timestamp in date and time format.",

1699 format: {type: :grammar, syntax: :regex, definition: grammar}

1700 }]

1701)

1702 

1703puts(response.output)

1704```

1705 

1466 1706 

1467The output from the tool should then conform to the Regex CFG that you defined:1707The output from the tool should then conform to the Regex CFG that you defined:

1468 1708 

Details

141}141}

142```142```

143 143 

144```ruby

145require "base64"

146require "openai"

147 

148client = OpenAI::Client.new

149result = client.images.generate(

150 model: "gpt-image-2",

151 prompt: "A watercolor robot reading in a library"

152)

153generated_image = result.data&.first or raise "No image returned"

154File.binwrite(

155 "generated-image.png",

156 Base64.strict_decode64(generated_image.b64_json)

157)

158```

159 

144```bash160```bash

145curl -X POST "https://api.openai.com/v1/images/generations" \161curl -X POST "https://api.openai.com/v1/images/generations" \

146 -H "Authorization: Bearer $OPENAI_API_KEY" \162 -H "Authorization: Bearer $OPENAI_API_KEY" \


261}277}

262```278```

263 279 

280```ruby

281require "base64"

282require "openai"

283 

284client = OpenAI::Client.new

285response = client.responses.create(

286 model: "gpt-5.6",

287 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

288 tools: [{type: :image_generation}]

289)

290 

291image_call = response.output.find do |item|

292 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

293end

294unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

295 raise "No image generation call returned"

296end

297 

298encoded_image = image_call.result or raise "No image returned"

299File.binwrite("otter.png", Base64.strict_decode64(encoded_image))

300```

301 

264 302 

265 303 

266### Multi-turn image generation304### Multi-turn image generation


361}399}

362```400```

363 401 

402```ruby

403require "base64"

404require "openai"

405 

406client = OpenAI::Client.new

407response = client.responses.create(

408 model: "gpt-5.6",

409 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

410 tools: [{type: :image_generation, action: :generate}]

411)

412 

413image_call = response.output.find do |item|

414 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

415end

416unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

417 raise "No image generation call returned"

418end

419 

420encoded_image = image_call.result or raise "No image returned"

421output_path = ENV.fetch("OPENAI_EXAMPLE_OUTPUT_PATH", "otter.png")

422File.binwrite(output_path, Base64.decode64(encoded_image))

423puts(output_path)

424```

425 

364 426 

365If you force `edit` without providing an image in context, the call will return an error. Leave `action` at `auto` to have the model decide when to generate or edit.427If you force `edit` without providing an image in context, the call will return an error. Leave `action` at `auto` to have the model decide when to generate or edit.

366 428 


518}580}

519```581```

520 582 

583```ruby

584require "base64"

585require "openai"

586 

587client = OpenAI::Client.new

588first = client.responses.create(

589 model: "gpt-5.6",

590 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

591 tools: [{type: :image_generation}]

592)

593 

594first_image = first.output.find do |item|

595 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

596end

597unless first_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

598 raise "No image generation call returned"

599end

600 

601encoded_image = first_image.result or raise "No image returned"

602File.binwrite("cat_and_otter.png", Base64.strict_decode64(encoded_image))

603 

604follow_up = client.responses.create(

605 model: "gpt-5.6",

606 input: "Now make it look realistic.",

607 previous_response_id: first.id,

608 tools: [{type: :image_generation}]

609)

610 

611follow_up_image = follow_up.output.find do |item|

612 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

613end

614unless follow_up_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

615 raise "No follow-up image generation call returned"

616end

617 

618encoded_image = follow_up_image.result or raise "No follow-up image returned"

619File.binwrite("cat_and_otter_realistic.png", Base64.strict_decode64(encoded_image))

620```

621 

521 622

522 623 

523 624


709}810}

710```811```

711 812 

813```ruby

814require "base64"

815require "openai"

816 

817client = OpenAI::Client.new

818first = client.responses.create(

819 model: "gpt-5.6",

820 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

821 tools: [{type: :image_generation}]

822)

823 

824first_image = first.output.find do |item|

825 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

826end

827unless first_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

828 raise "No image generation call returned"

829end

830 

831encoded_image = first_image.result or raise "No image returned"

832File.binwrite("cat_and_otter.png", Base64.strict_decode64(encoded_image))

833 

834follow_up = client.responses.create(

835 model: "gpt-5.6",

836 input: [

837 {

838 role: :user,

839 content: [{type: :input_text, text: "Now make it look realistic."}]

840 },

841 {type: :image_generation_call, id: first_image.id}

842 ],

843 tools: [{type: :image_generation}]

844)

845 

846follow_up_image = follow_up.output.find do |item|

847 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

848end

849unless follow_up_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

850 raise "No follow-up image generation call returned"

851end

852 

853encoded_image = follow_up_image.result or raise "No follow-up image returned"

854File.binwrite("cat_and_otter_realistic.png", Base64.strict_decode64(encoded_image))

855```

856 

712 857 

713 858 

714#### Result859#### Result


887}1032}

888```1033```

889 1034 

1035```ruby

1036require "base64"

1037require "openai"

1038 

1039client = OpenAI::Client.new

1040stream = client.responses.stream(

1041 model: "gpt-5.6",

1042 input: "Generate an image of a river made of white owl feathers.",

1043 tools: [{type: :image_generation, partial_images: 2}]

1044)

1045 

1046stream.each do |event|

1047 case event

1048 when OpenAI::Models::Responses::ResponseImageGenCallPartialImageEvent

1049 image = Base64.strict_decode64(event.partial_image_b64)

1050 File.binwrite("river-partial-#{event.partial_image_index}.png", image)

1051 when OpenAI::Models::Responses::ResponseCompletedEvent

1052 image_call = event.response.output.find do |item|

1053 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

1054 end

1055 next unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

1056 

1057 File.binwrite(

1058 "river-final.png",

1059 Base64.strict_decode64(image_call.result)

1060 )

1061 end

1062end

1063```

1064 

890 1065

891 1066 

892 1067


986}1161}

987```1162```

988 1163 

1164```ruby

1165require "base64"

1166require "openai"

1167 

1168client = OpenAI::Client.new

1169stream = client.images.generate_stream_raw(

1170 model: "gpt-image-2",

1171 prompt: "A river made of white owl feathers in a winter landscape",

1172 partial_images: 2

1173)

1174 

1175stream.each do |event|

1176 next unless event.is_a?(OpenAI::Models::ImageGenPartialImageEvent)

1177 

1178 image = Base64.strict_decode64(event.b64_json)

1179 File.binwrite("river#{event.partial_image_index}.png", image)

1180end

1181```

1182 

989 1183 

990 1184 

991#### Result1185#### Result


1115}1309}

1116```1310```

1117 1311 

1312```ruby

1313require "openai"

1314require "pathname"

1315 

1316client = OpenAI::Client.new

1317file = client.files.create(

1318 file: Pathname("image.png"),

1319 purpose: OpenAI::Models::FilePurpose::VISION

1320)

1321puts(file.id)

1322```

1323 

1118 1324 

1119#### Create a base64 encoded image1325#### Create a base64 encoded image

1120 1326 


1157}1363}

1158```1364```

1159 1365 

1366```ruby

1367require "base64"

1368 

1369image = File.binread("image.png")

1370puts(Base64.strict_encode64(image))

1371```

1372 

1160 1373 

1161Edit an image1374Edit an image

1162 1375 


1380}1593}

1381```1594```

1382 1595 

1596```ruby

1597require "base64"

1598require "openai"

1599require "pathname"

1600 

1601client = OpenAI::Client.new

1602base64_images = ["body-lotion.png", "soap.png"].map do |path|

1603 Base64.strict_encode64(File.binread(path))

1604end

1605file_ids = [

1606 client.files.create(file: Pathname("bath-bomb.png"), purpose: :vision).id,

1607 client.files.create(file: Pathname("incense-kit.png"), purpose: :vision).id

1608]

1609prompt = <<~PROMPT

1610 Generate a photorealistic image of a gift basket on a white background

1611 labeled 'Relax & Unwind' with a ribbon and handwriting-like font,

1612 containing all the items in the reference pictures.

1613PROMPT

1614response = client.responses.create(

1615 model: "gpt-5.6",

1616 input: [{

1617 role: :user,

1618 content: [

1619 {type: :input_text, text: prompt},

1620 *base64_images.map do |image|

1621 {type: :input_image, image_url: "data:image/png;base64,#{image}"}

1622 end,

1623 *file_ids.map do |file_id|

1624 {type: :input_image, file_id: file_id}

1625 end

1626 ]

1627 }],

1628 tools: [{type: :image_generation}]

1629)

1630 

1631image_call = response.output.find do |item|

1632 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

1633end

1634unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

1635 raise "No image generation call returned"

1636end

1637 

1638File.binwrite("gift-basket.png", Base64.strict_decode64(image_call.result))

1639```

1640 

1383 1641 

1384 1642

1385 1643 


1529}1787}

1530```1788```

1531 1789 

1790```ruby

1791require "base64"

1792require "openai"

1793require "pathname"

1794 

1795client = OpenAI::Client.new

1796images = %w[body-lotion.png bath-bomb.png incense-kit.png soap.png].map do |path|

1797 Pathname(path)

1798end

1799result = client.images.edit(

1800 image: images,

1801 model: "gpt-image-2",

1802 prompt: <<~PROMPT

1803 Generate a photorealistic image of a gift basket on a white background

1804 labeled 'Relax & Unwind' with a ribbon and handwriting-like font,

1805 containing all the items in the reference pictures.

1806 PROMPT

1807)

1808generated_image = result.data&.first or raise "No image returned"

1809File.binwrite("gift-basket.png", Base64.strict_decode64(generated_image.b64_json))

1810```

1811 

1532```bash1812```bash

1533curl -s -D >(grep -i x-request-id >&2) \1813curl -s -D >(grep -i x-request-id >&2) \

1534 -o >(jq -r '.data[0].b64_json' | base64 --decode > gift-basket.png) \1814 -o >(jq -r '.data[0].b64_json' | base64 --decode > gift-basket.png) \


1754}2034}

1755```2035```

1756 2036 

2037```ruby

2038require "base64"

2039require "openai"

2040require "pathname"

2041 

2042client = OpenAI::Client.new

2043image = client.files.create(file: Pathname("sunlit_lounge.png"), purpose: :vision)

2044mask = client.files.create(file: Pathname("mask.png"), purpose: :vision)

2045response = client.responses.create(

2046 model: "gpt-5.6",

2047 input: [{

2048 role: :user,

2049 content: [

2050 {type: :input_text, text: "Add a flamingo to the pool."},

2051 {type: :input_image, file_id: image.id}

2052 ]

2053 }],

2054 tools: [{

2055 type: :image_generation,

2056 input_image_mask: {file_id: mask.id}

2057 }]

2058)

2059 

2060image_call = response.output.find do |item|

2061 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

2062end

2063unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

2064 raise "No image generation call returned"

2065end

2066 

2067File.binwrite("lounge.png", Base64.strict_decode64(image_call.result))

2068```

2069 

1757 2070

1758 2071 

1759 2072


1850}2163}

1851```2164```

1852 2165 

2166```ruby

2167require "openai"

2168require "pathname"

2169require "base64"

2170 

2171client = OpenAI::Client.new

2172image = Pathname("sunlit_lounge.png")

2173mask = Pathname("mask.png")

2174result = client.images.edit(

2175 image: image,

2176 mask: mask,

2177 model: "gpt-image-2",

2178 prompt: "A sunlit indoor lounge area with a pool containing a flamingo"

2179)

2180generated_image = result.data&.first or raise "No image returned"

2181File.binwrite("lounge.png", Base64.strict_decode64(generated_image.b64_json))

2182```

2183 

1853```bash2184```bash

1854curl -s -D >(grep -i x-request-id >&2) \2185curl -s -D >(grep -i x-request-id >&2) \

1855 -o >(jq -r '.data[0].b64_json' | base64 --decode > lounge.png) \2186 -o >(jq -r '.data[0].b64_json' | base64 --decode > lounge.png) \


2283}2614}

2284```2615```

2285 2616 

2617```ruby

2618require "openai"

2619 

2620client = OpenAI::Client.new

2621begin

2622 client.images.generate(

2623 model: "gpt-image-2",

2624 prompt: "Create a poster humiliating my coworker with insulting captions"

2625 )

2626rescue OpenAI::Errors::BadRequestError => error

2627 raise unless error.code == "moderation_blocked"

2628 

2629 body = Hash.try_convert(error.body) || {}

2630 moderation_details = body[:moderation_details] || body["moderation_details"] || {}

2631 categories = moderation_details[:categories] || moderation_details["categories"] || []

2632 stage = moderation_details[:moderation_stage] || moderation_details["moderation_stage"]

2633 

2634 hint = "This request did not meet safety requirements."

2635 if categories.include?("harassment")

2636 hint = "Remove abusive or targeting language and focus on neutral visual details."

2637 elsif stage == "input"

2638 hint = "Revise the prompt or input images, then submit the request again."

2639 elsif stage == "output"

2640 hint = "Change the prompt and generate again; the generated result was blocked."

2641 end

2642 

2643 warn("Image generation blocked (#{error.code}): #{hint}")

2644end

2645```

2646 

2286 2647 

2287### Supported models2648### Supported models

2288 2649 

Details

132}132}

133```133```

134 134 

135```ruby

136require "base64"

137require "openai"

138 

139client = OpenAI::Client.new

140response = client.responses.create(

141 model: "gpt-5.6",

142 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

143 tools: [{type: :image_generation}]

144)

145 

146image_call = response.output.find do |item|

147 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

148end

149unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

150 raise "No image generation call returned"

151end

152 

153File.binwrite(

154 "cat_and_otter.png",

155 Base64.strict_decode64(image_call.result)

156)

157```

158 

135```bash159```bash

136openai responses create \160openai responses create \

137 --model gpt-5.6 \161 --model gpt-5.6 \


294Console.WriteLine(response.GetOutputText());318Console.WriteLine(response.GetOutputText());

295```319```

296 320 

321```ruby

322require "openai"

323 

324client = OpenAI::Client.new

325 

326response = client.responses.create(

327 model: "gpt-5.6",

328 input: [

329 {

330 role: :user,

331 content: [

332 {type: :input_text, text: "What's in this image?"},

333 {

334 type: :input_image,

335 detail: :auto,

336 image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg"

337 }

338 ]

339 }

340 ]

341)

342 

343puts(response.output_text)

344```

345 

297```bash346```bash

298curl https://api.openai.com/v1/responses \347curl https://api.openai.com/v1/responses \

299 -H "Content-Type: application/json" \348 -H "Content-Type: application/json" \


503Console.WriteLine($"From byte array: {response2.GetOutputText()}");552Console.WriteLine($"From byte array: {response2.GetOutputText()}");

504```553```

505 554 

555```ruby

556require "base64"

557require "openai"

558 

559client = OpenAI::Client.new

560image = Base64.strict_encode64(File.binread("image.png"))

561 

562response = client.responses.create(

563 model: "gpt-5.6",

564 input: [

565 {

566 role: :user,

567 content: [

568 {type: :input_text, text: "What's in this image?"},

569 {

570 type: :input_image,

571 detail: :auto,

572 image_url: "data:image/png;base64,#{image}"

573 }

574 ]

575 }

576 ]

577)

578 

579puts(response.output_text)

580```

581 

506 582

507 583 

508 584


683Console.WriteLine(response.GetOutputText());759Console.WriteLine(response.GetOutputText());

684```760```

685 761 

762```ruby

763require "openai"

764require "pathname"

765 

766client = OpenAI::Client.new

767uploaded = client.files.create(

768 file: Pathname("image.png"),

769 purpose: :vision

770)

771 

772response = client.responses.create(

773 model: "gpt-5.6",

774 input: [

775 {

776 role: :user,

777 content: [

778 {type: :input_text, text: "What's in this image?"},

779 {type: :input_image, detail: :auto, file_id: uploaded.id}

780 ]

781 }

782 ]

783)

784 

785puts(response.output_text)

786```

787 

686 788 

687 789 

688 790 

Details

2 2 

3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

4 4 

5This guide covers the core set of principles you can apply to improve latency across a wide variety of LLM-related use cases. These techniques come from working with a wide range of customers and developers on production applications, so they should apply regardless of what you're buildingfrom a granular workflow to an end-to-end chatbot.5This guide covers the core set of principles you can apply to improve latency across a wide variety of LLM-related use cases. These techniques come from working with a wide range of customers and developers on production applications, so they should apply regardless of what you're buildingfrom a granular workflow to an end-to-end chat application.

6 6 

7While there's many individual techniques, we'll be grouping them into **seven principles** meant to represent a high-level taxonomy of approaches for improving latency.7Although there are many individual techniques, this guide groups them into **seven principles** that represent a high-level taxonomy of approaches for improving latency.

8 8 

9At the end, we'll walk through an [example](#example) to see how they can be applied.9At the end, we'll walk through an [example](#example) to see how they can be applied.

10 10 


22 22 

23**Inference speed** is probably the first thing that comes to mind when addressing latency (but as you'll see soon, it's far from the only one). This refers to the actual **rate at which the LLM processes tokens**, and is often measured in TPM (tokens per minute) or TPS (tokens per second).23**Inference speed** is probably the first thing that comes to mind when addressing latency (but as you'll see soon, it's far from the only one). This refers to the actual **rate at which the LLM processes tokens**, and is often measured in TPM (tokens per minute) or TPS (tokens per second).

24 24 

25The main factor that influences inference speed is **model size**smaller models usually run faster (and cheaper), and when used correctly can even outperform larger models. To maintain high quality performance with smaller models you can explore:25The main factor that influences inference speed is **model size**smaller models usually run faster (and cheaper), and when used correctly can even outperform larger models. To maintain high-quality performance with smaller models, you can explore:

26 26 

27- using a longer, [more detailed prompt](https://developers.openai.com/api/docs/guides/prompt-engineering#prompt-engineering),27- using a longer, [more detailed prompt](https://developers.openai.com/api/docs/guides/prompt-engineering#prompt-engineering),

28- adding (more) [few-shot examples](https://developers.openai.com/api/docs/guides/prompt-engineering#few-shot-learning), or28- adding (more) [few-shot examples](https://developers.openai.com/api/docs/guides/prompt-engineering#few-shot-learning), or


48 48 

49## Generate fewer tokens49## Generate fewer tokens

50 50 

51Generating tokens is almost always the highest latency step when using an LLM: as a general heuristic, **cutting 50% of your output tokens may cut ~50% your latency**. The way you reduce your output size will depend on output type:51Generating tokens is almost always the highest latency step when using an LLM: as a general heuristic, **cutting 50% of your output tokens may cut ~50% of your latency**. The way you reduce your output size will depend on output type:

52 52 

53If you're generating **natural language**, simply **asking the model to be more concise** ("under 20 words" or "be very brief") may help. You can also use few shot examples and/or fine-tuning to teach the model shorter responses.53If you're generating **natural language**, **asking the model to be more concise** ("under 20 words" or "be brief") may help. You can also use few-shot examples and/or fine-tuning to teach the model shorter responses.

54 54 

55If you're generating **structured output**, try to **minimize your output syntax** where possible: shorten function names, omit named arguments, coalesce parameters, etc.55If you're generating **structured output**, try to **minimize your output syntax** where possible: shorten function names, omit named arguments, coalesce parameters, etc.

56 56 


60 60 

61## Use fewer input tokens61## Use fewer input tokens

62 62 

63While reducing the number of input tokens does result in lower latency, this is not usually a significant factor**cutting 50% of your prompt may only result in a 1-5% latency improvement**. Unless you're working with truly massive context sizes (documents, images), you may want to spend your efforts elsewhere.63While reducing the number of input tokens does result in lower latency, this is not usually a significant factor**cutting 50% of your prompt may only result in a 15% latency improvement**. Unless you're working with truly massive context sizes (documents, images), you may want to spend your efforts elsewhere.

64 64 

65That being said, if you _are_ working with massive contexts (or you're set on squeezing every last bit of performance _and_ you've exhausted all other options) you can use the following techniques to reduce your input tokens:65That being said, if you _are_ working with massive contexts (or you're set on squeezing every last bit of performance _and_ you've exhausted all other options) you can use the following techniques to reduce your input tokens:

66 66 

67- **Fine-tuning the model**, to replace the need for lengthy instructions / examples.67- **Fine-tuning the model**, to replace the need for lengthy instructions / examples.

68- **Filtering context input**, like pruning RAG results, cleaning HTML, etc.68- **Filtering context input**, like pruning RAG results, cleaning HTML, etc.

69- **Maximize shared prompt prefix**, by putting dynamic portions (e.g. RAG results, history, etc) later in the prompt. This makes your request more [KV cache](https://medium.com/@joaolages/kv-caching-explained-276520203249)-friendly (which most LLM providers use) and means fewer input tokens are processed on each request.69- **Maximize shared prompt prefix**, by putting dynamic portions (for example, RAG results and history) later in the prompt. This makes your request more [KV cache](https://medium.com/@joaolages/kv-caching-explained-276520203249)-friendly (which most LLM providers use) and means fewer input tokens are processed on each request.

70 70 

71Check out our docs to learn more about how [prompt71Check out our docs to learn more about how [prompt

72 caching](https://developers.openai.com/api/docs/guides/prompt-engineering#save-on-cost-and-latency-with-prompt-caching)72 caching](https://developers.openai.com/api/docs/guides/prompt-engineering#save-on-cost-and-latency-with-prompt-caching)


74 74 

75## Make fewer requests75## Make fewer requests

76 76 

77Each time you make a request you incur some round-trip latencythis can start to add up.77Each time you make a request, you incur some round-trip latencythis can start to add up.

78 78 

79If you have sequential steps for the LLM to perform, instead of firing off one request per step consider **putting them in a single prompt and getting them all in a single response**. You'll avoid the additional round-trip latency, and potentially also reduce complexity of processing multiple responses.79If you have sequential steps for the LLM to perform, instead of firing off one request per step consider **putting them in a single prompt and getting them all in a single response**. You'll avoid the additional round-trip latency, and potentially also reduce complexity of processing multiple responses.

80 80 

81An approach to doing this is by collecting your steps in an enumerated list in the combined prompt, and then requesting the model to return the results in named fields in a JSON. This way you can easily parse out and reference each result!81An approach to doing this is by collecting your steps in an enumerated list in the combined prompt, and then requesting the model to return the results in named fields in a JSON object. This way, you can parse and reference each result.

82 82 

83## Parallelize83## Parallelize

84 84 

85Parallelization can be very powerful when performing multiple steps with an LLM.85Parallel processing can be powerful when performing multiple steps with an LLM.

86 86 

87If the steps **are _not_ strictly sequential**, you can **split them out into parallel calls**. Two shirts take just as long to dry as one.87If the steps **are _not_ strictly sequential**, you can **split them out into parallel calls**. Two shirts take just as long to dry as one.

88 88 

89If the steps **_are_ strictly sequential**, however, you might still be able to **leverage speculative execution**. This is particularly effective for classification steps where one outcome is more likely than the others (e.g. moderation).89If the steps **_are_ strictly sequential**, however, you might still be able to **leverage speculative execution**. This is particularly effective for classification steps where one outcome is more likely than the others (for example, moderation).

90 90 

911. Start step 1 & step 2 simultaneously (e.g. input moderation & story generation)911. Start step 1 and step 2 simultaneously (for example, input moderation and story generation)

922. Verify the result of step 1922. Verify the result of step 1

933. If result was not the expected, cancel step 2 (and retry if necessary)933. If result was not the expected, cancel step 2 (and retry if necessary)

94 94 


96 96 

97## Make your users wait less97## Make your users wait less

98 98 

99There's a huge difference between **waiting** and **watching progress happen**make sure your users experience the latter. Here are a few techniques:99There's a huge difference between **waiting** and **watching progress happen**make sure your users experience the latter. Here are a few techniques:

100 100 

101- **Streaming**: The single most effective approach, as it cuts the _waiting_ time to a second or less. (ChatGPT would feel pretty different if you saw nothing until each response was done.)101- **Streaming**: The single most effective approach, as it cuts the _waiting_ time to a second or less. (ChatGPT would feel pretty different if you saw nothing until each response was done.)

102- **Chunking**: If your output needs further processing before being shown to the user (moderation, translation) consider **processing it in chunks** instead of all at once. Do this by streaming to your backend, then sending processed chunks to your frontend.102- **Chunking**: If your output needs further processing before being shown to the user (moderation, translation), consider **processing it in chunks** instead of all at once. Do this by streaming to your back end, then sending processed chunks to your front end.

103- **Show your steps**: If you're taking multiple steps or using tools, surface this to the user. The more real progress you can show, the better.103- **Show your steps**: If you're taking multiple steps or using tools, surface this to the user. The more real progress you can show, the better.

104- **Loading states**: Spinners and progress bars go a long way.104- **Loading states**: Spinners and progress bars go a long way.

105 105 


110 110 

111## Don't default to an LLM111## Don't default to an LLM

112 112 

113LLMs are extremely powerful and versatile, and are therefore sometimes used in cases where a **faster classical method** would be more appropriate. Identifying such cases may allow you to cut your latency significantly. Consider the following examples:113Language models are powerful and versatile, and are therefore sometimes used in cases where a **faster classical method** would be more appropriate. Identifying such cases may allow you to cut your latency significantly. Consider the following examples:

114 114 

115- **Hard-coding:** If your **output** is highly constrained, you may not need an LLM to generate it. Action confirmations, refusal messages, and requests for standard input are all great candidates to be hard-coded. (You can even use the age-old method of coming up with a few variations for each.)115- **Hard-coding:** If your **output** is highly constrained, you may not need an LLM to generate it. Action confirmations, refusal messages, and requests for standard input are all great candidates to be hard-coded. (You can even use the age-old method of coming up with a few variations for each.)

116- **Pre-computing:** If your **input** is constrained (e.g. category selection) you can generate multiple responses in advance, and just make sure you never show the same one to a user twice.116- **Pre-computing:** If your **input** is constrained (for example, category selection), you can generate multiple responses in advance, and just make sure you never show the same one to a user twice.

117- **Leveraging UI:** Summarized metrics, reports, or search results are sometimes better conveyed with classical, bespoke UI components rather than LLM-generated text.117- **Leveraging UI:** Summarized metrics, reports, or search results are sometimes better conveyed with classical, bespoke UI components rather than LLM-generated text.

118- **Traditional optimization techniques:** An LLM application is still an application; binary search, caching, hash maps, and runtime complexity are all _still_ useful in a world of LLMs.118- **Traditional optimization techniques:** An LLM application is still an application; binary search, caching, hash maps, and runtime complexity are all _still_ useful in a world of language models.

119 119 

120## Example120## Example

121 121 


243}243}

244```244```

245 245 

246```ruby

247combined_query = {

248 query: "[contextualized query]",

249 retrieval: "[true/false - whether retrieval is required]"

250}

251 

252puts(combined_query)

253```

254 

246 255 

247```example-chat256```example-chat

248SYSTEM: Given the previous conversation, re-write the last user query so it contains257SYSTEM: Given the previous conversation, re-write the last user query so it contains


276 285 

277 286 

278 287 

279Actually, adding context and determining whether to retrieve are very straightforward and well defined tasks, so we can likely use a **smaller, fine-tuned model** instead. Switching to GPT-3.5 will let us [process tokens faster](#process-tokens-faster).288Actually, adding context and determining whether to retrieve are straightforward and well-defined tasks, so we can likely use a **smaller, fine-tuned model** instead. Switching to GPT-3.5 will let us [process tokens faster](#process-tokens-faster).

280 289 

281![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-4.png)290![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-4.png)

282 291 

283#### Part 2: Analyzing the assistant prompt292#### Part 2: Analyzing the assistant prompt

284 293 

285Let's now direct our attention to the Assistant prompt. There seem to be many distinct steps happening as it fills the JSON fieldsthis could indicate an opportunity to [parallelize](#parallelize).294Let's now direct our attention to the Assistant prompt. There seem to be many distinct steps happening as it fills the JSON fieldsthis could indicate an opportunity to [parallelize](#parallelize).

286 295 

287![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-5.png)296![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-5.png)

288 297 

289However, let's pretend we have run some tests and discovered that splitting the reasoning steps in the JSON produces worse responses, so we need to explore different solutions.298However, let's pretend we have run some tests and discovered that splitting the reasoning steps in the JSON produces worse responses, so we need to explore different solutions.

290 299 

291**Could we use a fine-tuned GPT-3.5 instead of GPT-4?** Maybebut in general, open-ended responses from assistants are best left to GPT-4 so it can better handle a greater range of cases. That being said, looking at the reasoning steps themselves, they may not all require GPT-4 level reasoning to produce. The well defined, limited scope nature makes them and **good potential candidates for fine-tuning**.300**Could we use a fine-tuned GPT-3.5 instead of GPT-4?** Maybebut in general, open-ended responses from assistants are best left to GPT-4 so it can better handle a greater range of cases. That being said, looking at the reasoning steps themselves, they may not all require GPT-4-level reasoning to produce. Their well-defined, limited scope makes them **good potential candidates for fine-tuning**.

292 301 

293```javascript302```javascript

294{303{


304}313}

305```314```

306 315 

316```ruby

317assistant_response = {

318 message_is_conversation_continuation: "True", # <-

319 number_of_messages_in_conversation_so_far: "1", # <-

320 user_sentiment: "Aggravated", # <-

321 query_type: "Hardware Issue", # <-

322 response_tone: "Validating and solution-oriented", # <-

323 response_requirements: "Propose options for repair or replacement.", # <-

324 user_requesting_to_talk_to_human: "False", # <-

325 enough_information_in_context: "True", # <-

326 response: "..." # X -- benefits from GPT-4

327}

328 

329puts(assistant_response)

330```

331 

307 332 

308This opens up the possibility of a trade-off. Do we keep this as a **single request entirely generated by GPT-4**, or **split it into two sequential requests** and use GPT-3.5 for all but the final response? We have a case of conflicting principles: the first option lets us [make fewer requests](#make-fewer-requests), but the second may let us [process tokens faster](#process-tokens-faster).333This opens up the possibility of a trade-off. Do we keep this as a **single request entirely generated by GPT-4**, or **split it into two sequential requests** and use GPT-3.5 for all but the final response? We have a case of conflicting principles: the first option lets us [make fewer requests](#make-fewer-requests), but the second may let us [process tokens faster](#process-tokens-faster).

309 334 


313- The average latency decrease from processing most fields faster.338- The average latency decrease from processing most fields faster.

314- The average latency _increase_ from doing two requests instead of one.339- The average latency _increase_ from doing two requests instead of one.

315 340 

316The conclusion will vary by case, and the best way to make the determiation is by testing this with production examples. In this case let's pretend the tests indicated it's favorable to split the prompt in two to [process tokens faster](#process-tokens-faster).341The conclusion will vary by case, and the best way to make the determination is by testing this with production examples. In this case, let's pretend the tests indicated it's favorable to split the prompt in two to [process tokens faster](#process-tokens-faster).

317 342 

318![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-6.png)343![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-6.png)

319 344 


406}431}

407```432```

408 433 

434```ruby

435reasoning = {

436 message_is_conversation_continuation: "True", # <-

437 number_of_messages_in_conversation_so_far: "1", # <-

438 user_sentiment: "Aggravated", # <-

439 query_type: "Hardware Issue", # <-

440 response_tone: "Validating and solution-oriented", # <-

441 response_requirements: "Propose options for repair or replacement.", # <-

442 user_requesting_to_talk_to_human: "False" # <-

443}

444 

445puts(reasoning)

446```

447 

409 448 

410By making them shorter and moving explanations to the comments we can [generate fewer tokens](#generate-fewer-tokens).449By making them shorter and moving explanations to the comments we can [generate fewer tokens](#generate-fewer-tokens).

411 450 


421}460}

422```461```

423 462 

463```ruby

464reasoning = {

465 cont: "True", # whether last message is a continuation

466 n_msg: "1", # number of messages in the continued conversation

467 tone_in: "Aggravated", # sentiment of user query

468 type: "Hardware Issue", # type of the user query

469 tone_out: "Validating and solution-oriented", # desired tone for response

470 reqs: "Propose options for repair or replacement.", # response requirements

471 human: "False" # whether user wants to talk to a human

472}

473 

474puts(reasoning)

475```

476 

424 477 

425![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-8b.png)478![Assistants object architecture diagram](https://cdn.openai.com/API/docs/images/diagram-latency-customer-service-8b.png)

426 479 

Details

255response.to_dict()["output"]255response.to_dict()["output"]

256```256```

257 257 

258```ruby

259require "openai"

260 

261client = OpenAI::Client.new

262response = client.responses.create(

263 model: "gpt-4.1",

264 instructions: "Act as a coding agent. Inspect the reported failure, identify the smallest correct change, and explain how you would verify it.",

265 input: "The parser rejects an empty optional field even though the schema permits it. Diagnose the likely validation bug."

266)

267 

268puts(response.output_text)

269```

270 

258 271 

259```text272```text

260[{'id': 'msg_67fe92df26ac819182ffafce9ff4e4fc07c7e06242e51f8b',273[{'id': 'msg_67fe92df26ac819182ffafce9ff4e4fc07c7e06242e51f8b',


468response.to_dict()["output"]481response.to_dict()["output"]

469```482```

470 483 

484```ruby

485require "openai"

486 

487client = OpenAI::Client.new

488response = client.responses.create(

489 model: "gpt-4.1",

490 instructions: "You are a customer service assistant. Confirm the customer's goal, use only supplied account facts, and clearly explain the next action.",

491 input: "A customer says a replacement order still has not shipped. Draft a concise response."

492)

493 

494puts(response.output_text)

495```

496 

471 497 

472```text498```text

473[{'id': 'msg_67fe92d431548191b7ca6cd604b4784b06efc5beb16b3c5e',499[{'id': 'msg_67fe92d431548191b7ca6cd604b4784b06efc5beb16b3c5e',

Details

112}112}

113```113```

114 114 

115```ruby

116require "openai"

117 

118client = OpenAI::Client.new

119response = client.responses.create(

120 model: "gpt-5.2",

121 reasoning: {effort: :minimal},

122 input: "Explain the bug and propose a fix."

123)

124puts(response.output_text)

125```

126 

115```bash127```bash

116curl --request POST \128curl --request POST \

117 --url https://api.openai.com/v1/responses \129 --url https://api.openai.com/v1/responses \


195}207}

196```208```

197 209 

210```ruby

211require "openai"

212 

213client = OpenAI::Client.new

214response = client.responses.create(

215 model: "gpt-5.2",

216 text: {verbosity: :low},

217 input: "Explain the bug and propose a fix."

218)

219puts(response.output_text)

220```

221 

198```bash222```bash

199curl --request POST \223curl --request POST \

200 --url https://api.openai.com/v1/responses \224 --url https://api.openai.com/v1/responses \


680print(json.dumps(compacted_response.model_dump(), indent=2))704print(json.dumps(compacted_response.model_dump(), indent=2))

681```705```

682 706 

707```ruby

708require "openai"

709 

710client = OpenAI::Client.new

711response = client.responses.create(

712 model: "gpt-5.2",

713 input: [{role: :user, content: "Write a very long poem about a dog."}]

714)

715compaction = client.responses.compact(

716 model: "gpt-5.2",

717 input: [

718 {role: :user, content: "Write a very long poem about a dog."},

719 *response.output.map(&:to_h)

720 ]

721)

722 

723puts(compaction.output)

724```

725 

683 726 

684### 5. Agentic steerability & user updates727### 5. Agentic steerability & user updates

685 728 

Details

115}115}

116```116```

117 117 

118```ruby

119require "openai"

120 

121client = OpenAI::Client.new

122response = client.responses.create(

123 model: "gpt-5.4",

124 reasoning: {effort: :minimal},

125 input: "Explain the bug and propose a fix."

126)

127puts(response.output_text)

128```

129 

118```bash130```bash

119curl --request POST \131curl --request POST \

120 --url https://api.openai.com/v1/responses \132 --url https://api.openai.com/v1/responses \


198}210}

199```211```

200 212 

213```ruby

214require "openai"

215 

216client = OpenAI::Client.new

217response = client.responses.create(

218 model: "gpt-5.4",

219 text: {verbosity: :low},

220 input: "Explain the bug and propose a fix."

221)

222puts(response.output_text)

223```

224 

201```bash225```bash

202curl --request POST \226curl --request POST \

203 --url https://api.openai.com/v1/responses \227 --url https://api.openai.com/v1/responses \


462}486}

463```487```

464 488 

489```ruby

490require "openai"

491 

492client = OpenAI::Client.new

493response = client.responses.create(

494 model: "gpt-5.4",

495 reasoning: {effort: :medium},

496 input: "Explain the bug and propose a fix."

497)

498puts(response.output_text)

499```

500 

465 501 

466### GPT-5.4 parameter compatibility502### GPT-5.4 parameter compatibility

467 503 

Details

220}220}

221```221```

222 222 

223```ruby

224require "openai"

225 

226client = OpenAI::Client.new

227messages = [

228 {role: :system, content: "You are a helpful assistant."},

229 {role: :user, content: "Hello!"}

230]

231 

232completion = client.chat.completions.create(

233 model: "gpt-5.6",

234 messages: messages

235)

236puts(completion.choices.fetch(0).message.content)

237 

238response = client.responses.create(

239 model: "gpt-5.6",

240 input: messages

241)

242puts(response.output_text)

243```

244 

223```bash245```bash

224INPUT='[246INPUT='[

225 { "role": "system", "content": "You are a helpful assistant." },247 { "role": "system", "content": "You are a helpful assistant." },


308}330}

309```331```

310 332 

333```ruby

334require "openai"

335 

336client = OpenAI::Client.new

337 

338completion = client.chat.completions.create(

339 model: "gpt-5.6",

340 messages: [

341 {role: :system, content: "You are a helpful assistant."},

342 {role: :user, content: "Hello!"}

343 ]

344)

345 

346puts(completion.choices.fetch(0).message.content)

347```

348 

311```bash349```bash

312curl https://api.openai.com/v1/chat/completions \350curl https://api.openai.com/v1/chat/completions \

313 -H "Content-Type: application/json" \351 -H "Content-Type: application/json" \


383}421}

384```422```

385 423 

424```ruby

425require "openai"

426 

427client = OpenAI::Client.new

428 

429response = client.responses.create(

430 model: "gpt-5.6",

431 instructions: "You are a helpful assistant.",

432 input: "Hello!"

433)

434 

435puts(response.output_text)

436```

437 

386```bash438```bash

387curl https://api.openai.com/v1/responses \439curl https://api.openai.com/v1/responses \

388 -H "Content-Type: application/json" \440 -H "Content-Type: application/json" \


492}544}

493```545```

494 546 

547```ruby

548require "openai"

549 

550client = OpenAI::Client.new

551messages = [

552 {role: :system, content: "You are a helpful assistant."},

553 {role: :user, content: "What is the capital of France?"}

554]

555 

556first = client.chat.completions.create(

557 model: "gpt-5.6",

558 messages: messages

559)

560messages << {role: :assistant, content: first.choices.fetch(0).message.content}

561messages << {role: :user, content: "And its population?"}

562 

563second = client.chat.completions.create(

564 model: "gpt-5.6",

565 messages: messages

566)

567 

568puts(second.choices.fetch(0).message.content)

569```

570 

495 571 

496 572

497 573 


591 }667 }

592 return input668 return input

593}669}

670```

671 

672```ruby

673require "openai"

674 

675client = OpenAI::Client.new

676context = [{role: :user, content: "What is the capital of France?"}]

677 

678first = client.responses.create(

679 model: "gpt-5.6",

680 input: context

681)

682context.concat(first.output.map(&:to_h))

683context << {role: :user, content: "And its population?"}

684 

685second = client.responses.create(

686 model: "gpt-5.6",

687 input: context

688)

689 

690puts(second.output_text)

594```691```

595 692 

596 You can also use `previous_response_id` to reference the previous response693 You can also use `previous_response_id` to reference the previous response


661}758}

662```759```

663 760 

761```ruby

762require "openai"

763 

764client = OpenAI::Client.new

765 

766first = client.responses.create(

767 model: "gpt-5.6",

768 input: "What is the capital of France?",

769 store: true

770)

771 

772second = client.responses.create(

773 model: "gpt-5.6",

774 previous_response_id: first.id,

775 input: "And its population?",

776 store: true

777)

778 

779puts(second.output_text)

780```

781 

664 782 

665 783 

666Even when using `previous_response_id`, all previous input tokens for responses in the chain are billed as input tokens in the API.784Even when using `previous_response_id`, all previous input tokens for responses in the chain are billed as input tokens in the API.


865}983}

866```984```

867 985 

986```ruby

987require "openai"

988 

989client = OpenAI::Client.new

990schema = {

991 type: "object",

992 properties: {

993 name: {type: "string", minLength: 1},

994 age: {type: "number", minimum: 0, maximum: 130}

995 },

996 required: ["name", "age"],

997 additionalProperties: false

998}

999 

1000completion = client.chat.completions.create(

1001 model: "gpt-5.6",

1002 reasoning_effort: :medium,

1003 messages: [{role: :user, content: "Jane, 54 years old"}],

1004 response_format: {

1005 type: :json_schema,

1006 json_schema: {name: "person", strict: true, schema: schema}

1007 }

1008)

1009 

1010puts(completion.choices.fetch(0).message.content)

1011```

1012 

868```bash1013```bash

869curl https://api.openai.com/v1/chat/completions \1014curl https://api.openai.com/v1/chat/completions \

870 -H "Content-Type: application/json" \1015 -H "Content-Type: application/json" \


1006}1151}

1007```1152```

1008 1153 

1154```ruby

1155require "openai"

1156 

1157client = OpenAI::Client.new

1158schema = {

1159 type: "object",

1160 properties: {

1161 name: {type: "string", minLength: 1},

1162 age: {type: "number", minimum: 0, maximum: 130}

1163 },

1164 required: ["name", "age"],

1165 additionalProperties: false

1166}

1167 

1168response = client.responses.create(

1169 model: "gpt-5.6",

1170 input: "Jane, 54 years old",

1171 text: {

1172 format: {

1173 type: :json_schema,

1174 name: "person",

1175 strict: true,

1176 schema: schema

1177 }

1178 }

1179)

1180 

1181puts(response.output_text)

1182```

1183 

1009```bash1184```bash

1010curl https://api.openai.com/v1/responses \1185curl https://api.openai.com/v1/responses \

1011 -H "Content-Type: application/json" \1186 -H "Content-Type: application/json" \


1162}1337}

1163```1338```

1164 1339 

1340```ruby

1341require "openai"

1342 

1343client = OpenAI::Client.new

1344 

1345completion = client.chat.completions.create(

1346 model: "gpt-5.6",

1347 reasoning_effort: :none,

1348 messages: [

1349 {role: :system, content: "You are a helpful assistant."},

1350 {role: :user, content: "Who is the current president of France?"}

1351 ],

1352 functions: [

1353 {

1354 name: "web_search",

1355 description: "Search the web for information",

1356 parameters: {

1357 type: "object",

1358 properties: {query: {type: "string"}},

1359 required: ["query"]

1360 }

1361 }

1362 ]

1363)

1364 

1365puts(completion.choices.fetch(0).message)

1366```

1367 

1165```bash1368```bash

1166curl https://api.example.com/search \1369curl https://api.example.com/search \

1167 -G \1370 -G \


1226}1429}

1227```1430```

1228 1431 

1432```ruby

1433require "openai"

1434 

1435client = OpenAI::Client.new

1436 

1437response = client.responses.create(

1438 model: "gpt-5.6",

1439 input: "Who is the current president of France?",

1440 tools: [{type: :web_search}]

1441)

1442 

1443puts(response.output_text)

1444```

1445 

1229```bash1446```bash

1230curl https://api.openai.com/v1/responses \1447curl https://api.openai.com/v1/responses \

1231 -H "Content-Type: application/json" \1448 -H "Content-Type: application/json" \

Details

134}134}

135```135```

136 136 

137```ruby

138require "openai"

139 

140client = OpenAI::Client.new

141 

142response = client.responses.create(

143 model: "gpt-5.6",

144 input: "A user asks for instructions to make a harmful weapon. Draft a brief refusal and offer a safer alternative.",

145 moderation: {model: "omni-moderation-latest"}

146)

147 

148puts(response.moderation)

149```

150 

137 151 

138The Responses API returns an input `moderation_result` object at `response.moderation.input` and an output `moderation_result` object at `response.moderation.output`.152The Responses API returns an input `moderation_result` object at `response.moderation.input` and an output `moderation_result` object at `response.moderation.output`.

139 153 


213}227}

214```228```

215 229 

230```ruby

231require "openai"

232 

233client = OpenAI::Client.new

234 

235moderation = client.moderations.create(

236 model: OpenAI::Models::ModerationModel::OMNI_MODERATION_LATEST,

237 input: "Text to classify goes here."

238)

239 

240puts(moderation.results.fetch(0).flagged)

241```

242 

216```bash243```bash

217curl https://api.openai.com/v1/moderations \244curl https://api.openai.com/v1/moderations \

218 -X POST \245 -X POST \


313}340}

314```341```

315 342 

343```ruby

344require "openai"

345 

346client = OpenAI::Client.new

347 

348moderation = client.moderations.create(

349 model: OpenAI::Models::ModerationModel::OMNI_MODERATION_LATEST,

350 input: [

351 {type: :text, text: "Text to classify goes here."},

352 {

353 type: :image_url,

354 image_url: {

355 url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg"

356 }

357 }

358 ]

359)

360 

361puts(moderation.results.fetch(0).flagged)

362```

363 

316```bash364```bash

317curl https://api.openai.com/v1/moderations \365curl https://api.openai.com/v1/moderations \

318 -X POST \366 -X POST \

Details

149}149}

150```150```

151 151 

152```ruby

153require "openai"

154 

155client = OpenAI::Client.new

156code = <<~CODE

157 class User {

158 firstName: string = "";

159 lastName: string = "";

160 username: string = "";

161 }

162 

163 export default User;

164CODE

165refactor_prompt = <<~PROMPT

166 Replace the "username" property with an "email" property. Respond only

167 with code, and with no markdown formatting.

168PROMPT

169completion = client.chat.completions.create(

170 model: "gpt-4.1",

171 messages: [

172 {role: :user, content: refactor_prompt},

173 {role: :user, content: code}

174 ],

175 prediction: {type: :content, content: code},

176 store: true

177)

178 

179puts(completion.choices.fetch(0).message.content)

180```

181 

152```bash182```bash

153curl https://api.openai.com/v1/chat/completions \183curl https://api.openai.com/v1/chat/completions \

154 -H "Content-Type: application/json" \184 -H "Content-Type: application/json" \


339}369}

340```370```

341 371 

372```ruby

373require "openai"

374 

375client = OpenAI::Client.new

376code = <<~CODE

377 class User {

378 firstName: string = "";

379 lastName: string = "";

380 username: string = "";

381 }

382 

383 export default User;

384CODE

385refactor_prompt = <<~PROMPT

386 Replace the "username" property with an "email" property. Respond only

387 with code, and with no markdown formatting.

388PROMPT

389stream = client.chat.completions.stream(

390 model: "gpt-4.1",

391 messages: [

392 {role: :user, content: refactor_prompt},

393 {role: :user, content: code}

394 ],

395 prediction: {type: :content, content: code},

396 store: true

397)

398 

399stream.text.each { |text| print(text) }

400```

401 

342 402 

343## Position of predicted text in response403## Position of predicted text in response

344 404 

Details

254}254}

255```255```

256 256 

257```ruby

258require "openai"

259 

260client = OpenAI::Client.new

261response = client.responses.create(

262 model: "gpt-5.6",

263 instructions: "Talk like a pirate.",

264 reasoning: {effort: :low},

265 input: "Are semicolons optional in JavaScript?"

266)

267 

268puts(response.output_text)

269```

270 

257```bash271```bash

258curl "https://api.openai.com/v1/responses" \272curl "https://api.openai.com/v1/responses" \

259 -H "Content-Type: application/json" \273 -H "Content-Type: application/json" \


350}364}

351```365```

352 366 

367```ruby

368require "openai"

369 

370client = OpenAI::Client.new

371response = client.responses.create(

372 model: "gpt-5.6",

373 reasoning: {effort: :low},

374 input: [

375 {role: :developer, content: "Talk like a pirate."},

376 {role: :user, content: "Are semicolons optional in JavaScript?"}

377 ]

378)

379 

380puts(response.output_text)

381```

382 

353```bash383```bash

354curl "https://api.openai.com/v1/responses" \384curl "https://api.openai.com/v1/responses" \

355 -H "Content-Type: application/json" \385 -H "Content-Type: application/json" \


535}565}

536```566```

537 567 

568```ruby

569require "openai"

570 

571client = OpenAI::Client.new

572instructions = File.read(File.join(__dir__, "prompt.txt"))

573response = client.responses.create(

574 model: "gpt-5.6",

575 instructions: instructions,

576 input: "How would I declare a variable for a last name?"

577)

578 

579puts(response.output_text)

580```

581 

538```bash582```bash

539curl https://api.openai.com/v1/responses \583curl https://api.openai.com/v1/responses \

540 -H "Authorization: Bearer $OPENAI_API_KEY" \584 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

81}81}

82```82```

83 83 

84```ruby

85require "openai"

86 

87client = OpenAI::Client.new

88 

89response = client.responses.create(

90 prompt: {

91 id: "pmpt_123",

92 version: "1",

93 variables: {

94 customer_name: "Acme",

95 issue: "billing question"

96 }

97 }

98)

99 

100puts(response.output_text)

101```

102 

84```bash103```bash

85curl https://api.openai.com/v1/responses \104curl https://api.openai.com/v1/responses \

86 -H "Content-Type: application/json" \105 -H "Content-Type: application/json" \


175}194}

176```195```

177 196 

197```ruby

198require "openai"

199 

200client = OpenAI::Client.new

201 

202response = client.responses.create(

203 model: "gpt-5.6",

204 input: [

205 {

206 role: :system,

207 content: "You are a helpful support assistant. Be concise, accurate, and friendly."

208 },

209 {

210 role: :user,

211 content: "Customer name: Acme. Issue: billing question. Write a response to the customer."

212 }

213 ]

214)

215 

216puts(response.output_text)

217```

218 

178```bash219```bash

179curl https://api.openai.com/v1/responses \220curl https://api.openai.com/v1/responses \

180 -H "Content-Type: application/json" \221 -H "Content-Type: application/json" \


305}346}

306```347```

307 348 

349```ruby

350require "openai"

351 

352def build_support_prompt(customer_name, issue)

353 [

354 {

355 role: :system,

356 content: "You are a helpful support assistant. Be concise, accurate, and friendly. Do not invent policy details."

357 },

358 {

359 role: :user,

360 content: "Customer name: #{customer_name}. Issue: #{issue}. Write a response to the customer."

361 }

362 ]

363end

364 

365client = OpenAI::Client.new

366 

367response = client.responses.create(

368 model: "gpt-5.6",

369 input: build_support_prompt("Acme", "billing question")

370)

371 

372puts(response.output_text)

373```

374 

308 375 

309## What you gain376## What you gain

310 377 

guides/rbac.md +9 −0

Details

59 59 

60 60 

61 61 

62#### Batch permission implications

63 

64Batch permissions include access required to prepare batch input files, execute requests, and retrieve results. This effective access is separate from the endpoints that can be submitted inside a batch, which are listed in the [Batch API guide](https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file).

65 

66| Batch permission | Additional access granted |

67| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

68| Read (`api.batch.read`) | Files Read (`api.files.read`) for `/v1/files` |

69| Write (`api.batch.write`) | Batch Read<br />List models (`api.model.read` and `model.read`) for `/v1/models`<br />Files Read and Write (`api.files.read` and `api.files.write`) for `/v1/files`<br />Model capabilities Request (`api.model.request` and `model.request`) for `/v1/audio`, `/v1/chat/completions`, `/v1/embeddings`, `/v1/images`, `/v1/moderations`, `/v1/realtime`, and `/v1/responses`<br />Videos Read and Write (`api.videos.read` and `api.videos.write`) for `/v1/videos` |

70 

62## Setting up RBAC71## Setting up RBAC

63 72 

64Allow up to **30 minutes** for role changes and group sync to propagate.73Allow up to **30 minutes** for role changes and group sync to propagate.

Details

93}93}

94```94```

95 95 

96```ruby

97require "openai"

98 

99client = OpenAI::Client.new

100prompt = <<~PROMPT

101 Write a bash script that takes a matrix represented as a string with format

102 '[1,2],[3,4],[5,6]' and prints the transpose in the same format.

103PROMPT

104 

105response = client.responses.create(

106 model: "gpt-5.6",

107 reasoning: {effort: :low},

108 input: prompt

109)

110 

111puts(response.output_text)

112```

113 

96```bash114```bash

97curl https://api.openai.com/v1/responses \115curl https://api.openai.com/v1/responses \

98 -H "Content-Type: application/json" \116 -H "Content-Type: application/json" \


308}326}

309```327```

310 328 

329```ruby

330require "openai"

331 

332client = OpenAI::Client.new

333prompt = <<~PROMPT

334 Write a bash script that takes a matrix represented as a string with format

335 '[1,2],[3,4],[5,6]' and prints the transpose in the same format.

336PROMPT

337 

338response = client.responses.create(

339 model: "gpt-5.6",

340 max_output_tokens: 300,

341 reasoning: {effort: :medium},

342 input: prompt

343)

344 

345if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE

346 puts("Ran out of tokens")

347 puts("Partial output: #{response.output_text}") unless response.output_text.empty?

348end

349```

350 

311 351 

312### Keeping reasoning items in context352### Keeping reasoning items in context

313 353 


435}475}

436```476```

437 477 

478```ruby

479require "openai"

480 

481client = OpenAI::Client.new

482 

483first = client.responses.create(

484 model: "gpt-5.6",

485 input: "Inspect this repository and identify the likely bug.",

486 reasoning: {context: :current_turn}

487)

488 

489second = client.responses.create(

490 model: "gpt-5.6",

491 previous_response_id: first.id,

492 input: "Now patch the bug and explain the change.",

493 reasoning: {context: :all_turns}

494)

495 

496puts(second.output_text)

497```

498 

438 499 

439Use `current_turn` when replaying older response items that the model no longer needs. Those reasoning items can remain in the API payload for continuity, but the service does not render them into the new sample. This can reduce the rendered context for long-running workflows.500Use `current_turn` when replaying older response items that the model no longer needs. Those reasoning items can remain in the API payload for continuity, but the service does not render them into the new sample. This can reduce the rendered context for long-running workflows.

440 501 


597}658}

598```659```

599 660 

661```ruby

662require "openai"

663 

664client = OpenAI::Client.new

665history = [

666 {role: :user, content: "Inspect this repository and identify the likely bug."}

667]

668 

669first = client.responses.create(

670 model: "gpt-5.6",

671 store: false,

672 input: history,

673 reasoning: {context: :current_turn}

674)

675history.concat(first.output.map(&:to_h))

676history << {role: :user, content: "Now patch the bug and explain the change."}

677 

678second = client.responses.create(

679 model: "gpt-5.6",

680 store: false,

681 input: history,

682 reasoning: {context: :all_turns}

683)

684 

685puts(second.output_text)

686```

687 

600 688 

601## Reasoning summaries689## Reasoning summaries

602 690 


672}760}

673```761```

674 762 

763```ruby

764require "openai"

765 

766client = OpenAI::Client.new

767 

768response = client.responses.create(

769 model: "gpt-5.6",

770 input: "What is the capital of France?",

771 reasoning: {effort: :low, summary: :auto}

772)

773 

774puts(response.output)

775```

776 

675```bash777```bash

676curl https://api.openai.com/v1/responses \778curl https://api.openai.com/v1/responses \

677 -H "Content-Type: application/json" \779 -H "Content-Type: application/json" \


829}931}

830```932```

831 933 

934```ruby

935require "openai"

936 

937client = OpenAI::Client.new

938 

939response = client.responses.create(

940 model: "gpt-5.6",

941 input: [

942 {

943 role: :assistant,

944 phase: :commentary,

945 content: "I'll inspect the logs and then summarize root cause and remediation."

946 },

947 {

948 role: :assistant,

949 phase: :final_answer,

950 content: "Root cause: cache invalidation race."

951 },

952 {

953 role: :user,

954 content: "Great—now give me a rollout-safe fix plan."

955 }

956 ]

957)

958 

959puts(response.output_text)

960```

961 

832 962 

833## Advice on prompting963## Advice on prompting

834 964 


985}1115}

986```1116```

987 1117 

1118```ruby

1119require "openai"

1120 

1121client = OpenAI::Client.new

1122prompt = <<~PROMPT

1123 Instructions:

1124 - Given the React component below, change it so that nonfiction books have red text.

1125 - Return only the code in your reply.

1126 - Do not include any additional formatting, such as markdown code blocks.

1127 

1128 const books = [

1129 { title: 'Dune', category: 'fiction', id: 1 },

1130 { title: 'Frankenstein', category: 'fiction', id: 2 },

1131 { title: 'Moneyball', category: 'nonfiction', id: 3 },

1132 ];

1133PROMPT

1134 

1135response = client.responses.create(

1136 model: "gpt-5.6",

1137 input: prompt

1138)

1139 

1140puts(response.output_text)

1141```

1142 

988 1143 

989 1144

990 1145 


1091}1246}

1092```1247```

1093 1248 

1249```ruby

1250require "openai"

1251 

1252client = OpenAI::Client.new

1253prompt = <<~PROMPT

1254 I want to build a Python app that looks up user questions in a database where

1255 they are mapped to answers. If there is a close match, it retrieves the answer.

1256 Otherwise, it asks the user for an answer and stores the question and answer.

1257 Plan the directory structure, then return each file in full.

1258PROMPT

1259 

1260response = client.responses.create(

1261 model: "gpt-5.6",

1262 input: prompt

1263)

1264 

1265puts(response.output_text)

1266```

1267 

1094 1268 

1095 1269

1096 1270 


1180}1354}

1181```1355```

1182 1356 

1357```ruby

1358require "openai"

1359 

1360client = OpenAI::Client.new

1361prompt = <<~PROMPT

1362 What are three compounds we should consider investigating to advance research

1363 into new antibiotics? Why should we consider them?

1364PROMPT

1365 

1366response = client.responses.create(

1367 model: "gpt-5.6",

1368 input: prompt

1369)

1370 

1371puts(response.output_text)

1372```

1373 

1183 1374 

1184 1375 

1185## Use case examples1376## Use case examples

Details

80}80}

81```81```

82 82 

83```ruby

84require "openai"

85require "pathname"

86 

87client = OpenAI::Client.new

88store = client.vector_stores.create(name: "Support FAQ")

89source = Pathname("customer_policies.txt")

90uploaded = client.files.create(file: source, purpose: :assistants)

91file = client.vector_stores.files.create(store.id, file_id: uploaded.id)

92until [:completed, :failed, :cancelled].include?(file.status)

93 sleep(1)

94 file = client.vector_stores.files.retrieve(file.id, vector_store_id: store.id)

95end

96 

97puts(store.id)

98```

99 

83 100 

84<li className={s.StandaloneLi} data-number={2}>101<li className={s.StandaloneLi} data-number={2}>

85 **Send search query** to get relevant results.102 **Send search query** to get relevant results.


126}143}

127```144```

128 145 

146```ruby

147require "openai"

148 

149client = OpenAI::Client.new

150results = client.vector_stores.search("vs_123", query: "What is the return policy?")

151puts(results.data&.first&.content)

152```

153 

129 154 

130To learn how to use the results with our models, check out the [synthesizing155To learn how to use the results with our models, check out the [synthesizing

131 responses](#synthesizing-responses) section.156 responses](#synthesizing-responses) section.


189}214}

190```215```

191 216 

217```ruby

218require "openai"

219 

220client = OpenAI::Client.new

221results = client.vector_stores.search(

222 "vs_123",

223 query: "How many woodchucks are allowed per passenger?"

224)

225puts(results.data&.first&.content)

226```

227 

192 228 

193Results229Results

194 230 


477}513}

478```514```

479 515 

516```ruby

517require "openai"

518 

519client = OpenAI::Client.new

520store = client.vector_stores.create(

521 name: "Support FAQ",

522 file_ids: ["file_123"]

523)

524puts(store.id)

525```

526 

480 527

481 528 

482 529


516}563}

517```564```

518 565 

566```ruby

567require "openai"

568 

569client = OpenAI::Client.new

570store = client.vector_stores.retrieve("vs_123")

571puts(store.id)

572```

573 

519 574

520 575 

521 576


560}615}

561```616```

562 617 

618```ruby

619require "openai"

620 

621client = OpenAI::Client.new

622store = client.vector_stores.update("vs_123", name: "Updated knowledge base")

623puts(store.name)

624```

625 

563 626

564 627 

565 628


599}662}

600```663```

601 664 

665```ruby

666require "openai"

667 

668client = OpenAI::Client.new

669deleted = client.vector_stores.delete("vs_123")

670puts(deleted.deleted)

671```

672 

602 673

603 674 

604 675


636}707}

637```708```

638 709 

710```ruby

711require "openai"

712 

713client = OpenAI::Client.new

714stores = client.vector_stores.list(limit: 10)

715puts((stores.data || []).length)

716```

717 

639 718 

640 719 

641### Vector store file operations720### Vector store file operations


685}764}

686```765```

687 766 

767```ruby

768require "openai"

769 

770client = OpenAI::Client.new

771file = client.vector_stores.files.create("vs_123", file_id: "file_123")

772puts(file.id)

773```

774 

688 775

689 776 

690 777


737}824}

738```825```

739 826 

827```ruby

828require "openai"

829require "pathname"

830 

831client = OpenAI::Client.new

832file = Pathname("customer_policies.txt")

833uploaded = client.files.create(file: file, purpose: :assistants)

834vector_store_file = client.vector_stores.files.create(

835 "vs_123",

836 file_id: uploaded.id

837)

838until [:completed, :failed, :cancelled].include?(vector_store_file.status)

839 sleep(1)

840 vector_store_file = client.vector_stores.files.retrieve(

841 vector_store_file.id,

842 vector_store_id: "vs_123"

843 )

844end

845puts(vector_store_file.id)

846```

847 

740 848

741 849 

742 850


779}887}

780```888```

781 889 

890```ruby

891require "openai"

892 

893client = OpenAI::Client.new

894file = client.vector_stores.files.retrieve("file_123", vector_store_id: "vs_123")

895puts(file.id)

896```

897 

782 898

783 899 

784 900


827}943}

828```944```

829 945 

946```ruby

947require "openai"

948 

949client = OpenAI::Client.new

950file = client.vector_stores.files.update("file_123", vector_store_id: "vs_123", attributes: {category: "policy"})

951puts(file.id)

952```

953 

830 954

831 955 

832 956


869}993}

870```994```

871 995 

996```ruby

997require "openai"

998 

999client = OpenAI::Client.new

1000deleted = client.vector_stores.files.delete("file_123", vector_store_id: "vs_123")

1001puts(deleted.deleted)

1002```

1003 

872 1004

873 1005 

874 1006


908}1040}

909```1041```

910 1042 

1043```ruby

1044require "openai"

1045 

1046client = OpenAI::Client.new

1047files = client.vector_stores.files.list("vs_123")

1048puts((files.data || []).length)

1049```

1050 

911 1051 

912 1052 

913### Batch operations1053### Batch operations


994}1134}

995```1135```

996 1136 

1137```ruby

1138require "openai"

1139 

1140client = OpenAI::Client.new

1141batch = client.vector_stores.file_batches.create(

1142 "vs_123",

1143 files: [

1144 {file_id: "file_123", attributes: {department: "finance"}},

1145 {

1146 file_id: "file_456",

1147 chunking_strategy: {

1148 type: :static,

1149 max_chunk_size_tokens: 1_200,

1150 chunk_overlap_tokens: 200

1151 }

1152 }

1153 ]

1154)

1155until [:completed, :failed, :cancelled].include?(batch.status)

1156 sleep(1)

1157 batch = client.vector_stores.file_batches.retrieve(

1158 batch.id,

1159 vector_store_id: "vs_123"

1160 )

1161end

1162puts(batch.status)

1163```

1164 

997 1165

998 1166 

999 1167


1036}1204}

1037```1205```

1038 1206 

1207```ruby

1208require "openai"

1209 

1210client = OpenAI::Client.new

1211batch = client.vector_stores.file_batches.retrieve(

1212 "vsfb_123",

1213 vector_store_id: "vs_123"

1214)

1215puts(batch.status)

1216```

1217 

1039 1218

1040 1219 

1041 1220


1078}1257}

1079```1258```

1080 1259 

1260```ruby

1261require "openai"

1262 

1263client = OpenAI::Client.new

1264batch = client.vector_stores.file_batches.cancel(

1265 "vsfb_123",

1266 vector_store_id: "vs_123"

1267)

1268puts(batch.status)

1269```

1270 

1081 1271

1082 1272 

1083 1273


1120}1310}

1121```1311```

1122 1312 

1313```ruby

1314require "openai"

1315 

1316client = OpenAI::Client.new

1317files = client.vector_stores.file_batches.list_files(

1318 "vsfb_123",

1319 vector_store_id: "vs_123"

1320)

1321puts((files.data || []).length)

1322```

1323 

1123 1324 

1124 1325 

1125When creating a batch you can either provide `file_ids` with optional `attributes` and/or `chunking_strategy`, or use the `files` array to pass objects that include a `file_id` plus optional `attributes` and `chunking_strategy` for each file. The two options are mutually exclusive so that you can cleanly control whether every file shares the same settings or you need per-file overrides.1326When creating a batch you can either provide `file_ids` with optional `attributes` and/or `chunking_strategy`, or use the `files` array to pass objects that include a `file_id` plus optional `attributes` and `chunking_strategy` for each file. The two options are mutually exclusive so that you can cleanly control whether every file shares the same settings or you need per-file overrides.


1182}1383}

1183```1384```

1184 1385 

1386```ruby

1387require "openai"

1388 

1389client = OpenAI::Client.new

1390file = client.vector_stores.files.create("<vector_store_id>", file_id: "file_123", attributes: {category: "policy"})

1391puts(file.id)

1392```

1393 

1185 1394 

1186### Expiration policies1395### Expiration policies

1187 1396 


1230}1439}

1231```1440```

1232 1441 

1442```ruby

1443require "openai"

1444 

1445client = OpenAI::Client.new

1446store = client.vector_stores.update(

1447 "vs_123",

1448 expires_after: {anchor: :last_active_at, days: 7}

1449)

1450puts(store.expires_after)

1451```

1452 

1233 1453 

1234### Limits1454### Limits

1235 1455 


1328}1548}

1329```1549```

1330 1550 

1551```ruby

1552require "openai"

1553 

1554client = OpenAI::Client.new

1555results = client.vector_stores.search(

1556 "vs_123",

1557 query: "What is the return policy?"

1558)

1559puts(results.data)

1560```

1561 

1331 1562 

1332Synthesize a response based on results1563Synthesize a response based on results

1333 1564 


1427}1658}

1428```1659```

1429 1660 

1661```ruby

1662require "openai"

1663 

1664client = OpenAI::Client.new

1665query = "What is the return policy?"

1666results = client.vector_stores.search("vs_123", query: query)

1667sources = (results.data || []).map do |result|

1668 content = result.content.map { |part| "<content>#{part.text}</content>" }.join

1669 "<result file_id='#{result.file_id}' file_name='#{result.filename}'>#{content}</result>"

1670end.join

1671 

1672completion = client.chat.completions.create(

1673 model: "gpt-5.6",

1674 messages: [

1675 {

1676 role: :developer,

1677 content: "Answer the query concisely using only the provided sources."

1678 },

1679 {role: :user, content: "Sources: <sources>#{sources}</sources>\n\nQuery: #{query}"}

1680 ]

1681)

1682puts(completion.choices.fetch(0).message.content)

1683```

1684 

1430 1685 

1431```json1686```json

1432"Our return policy allows returns within 30 days of purchase."1687"Our return policy allows returns within 30 days of purchase."


1497 return sources.String()1752 return sources.String()

1498}1753}

1499```1754```

1755 

1756```ruby

1757results = [

1758 {

1759 file_id: "file-12345",

1760 filename: "woodchuck_policy.txt",

1761 content: [{text: "Each passenger may carry up to two woodchucks."}]

1762 }

1763]

1764 

1765sources = results.map do |result|

1766 content = result.fetch(:content).map { |part| "<content>#{part.fetch(:text)}</content>" }.join

1767 "<result file_id=\"#{result.fetch(:file_id)}\" file_name=\"#{result.fetch(:filename)}\">#{content}</result>"

1768end

1769 

1770puts("<sources>#{sources.join}</sources>")

1771```

Details

100}100}

101```101```

102 102 

103```ruby

104require "openai"

105 

106client = OpenAI::Client.new

107completion = client.chat.completions.create(

108 model: "gpt-5.6",

109 messages: [{role: :user, content: "Help me plan a study schedule."}],

110 safety_identifier: "user_1234"

111)

112 

113puts(completion.choices.fetch(0).message.content)

114```

115 

103```bash116```bash

104curl https://api.openai.com/v1/chat/completions \117curl https://api.openai.com/v1/chat/completions \

105-H "Content-Type: application/json" \118-H "Content-Type: application/json" \

Details

70}70}

71```71```

72 72 

73```ruby

74require "openai"

75 

76client = OpenAI::Client.new

77response = client.responses.create(

78 model: "gpt-5.6-terra",

79 input: "Help me plan a study schedule.",

80 safety_identifier: "user_1234"

81)

82 

83puts(response.output_text)

84```

85 

73```bash86```bash

74curl https://api.openai.com/v1/responses \87curl https://api.openai.com/v1/responses \

75-H "Content-Type: application/json" \88-H "Content-Type: application/json" \


126}139}

127```140```

128 141 

142```ruby

143require "openai"

144 

145client = OpenAI::Client.new

146completion = client.chat.completions.create(

147 model: "gpt-5.6-terra",

148 messages: [{role: :user, content: "Help me plan a study schedule."}],

149 safety_identifier: "user_1234"

150)

151 

152puts(completion.choices.fetch(0).message.content)

153```

154 

129```bash155```bash

130curl https://api.openai.com/v1/chat/completions \156curl https://api.openai.com/v1/chat/completions \

131-H "Content-Type: application/json" \157-H "Content-Type: application/json" \

Details

76}76}

77```77```

78 78 

79```ruby

80require "openai"

81require "pathname"

82 

83client = OpenAI::Client.new

84audio = Pathname("audio.wav")

85transcript = client.audio.transcriptions.create(

86 file: audio,

87 model: "gpt-transcribe"

88)

89puts(transcript.text)

90```

91 

79```bash92```bash

80openai audio:transcriptions create \93openai audio:transcriptions create \

81 --model gpt-transcribe \94 --model gpt-transcribe \


189}202}

190```203```

191 204 

205```ruby

206require "openai"

207require "pathname"

208 

209client = OpenAI::Client.new

210audio = Pathname("audio.wav")

211transcript = client.audio.transcriptions.create(

212 file: audio,

213 model: "gpt-transcribe",

214 keywords: ["OpenAI", "Responses API", "Codex"]

215)

216puts(transcript.text)

217```

218 

192```bash219```bash

193curl https://api.openai.com/v1/audio/transcriptions \220curl https://api.openai.com/v1/audio/transcriptions \

194 -H "Authorization: Bearer $OPENAI_API_KEY" \221 -H "Authorization: Bearer $OPENAI_API_KEY" \


338}365}

339```366```

340 367 

368```ruby

369require "base64"

370require "openai"

371require "pathname"

372 

373client = OpenAI::Client.new

374audio = Pathname("meeting.wav")

375speaker_reference = Base64.strict_encode64(File.binread("agent.wav"))

376transcript = client.audio.transcriptions.create(

377 file: audio,

378 model: "gpt-4o-transcribe-diarize",

379 response_format: :diarized_json,

380 chunking_strategy: :auto,

381 known_speaker_names: ["agent"],

382 known_speaker_references: ["data:audio/wav;base64,#{speaker_reference}"]

383)

384segments = Array(transcript.to_h.fetch(:segments) do

385 raise "The transcription did not include speaker segments"

386end)

387segments.each do |segment|

388 segment = Hash.try_convert(segment) or raise "Invalid speaker segment"

389 puts(

390 "#{segment.fetch(:speaker)}: #{segment.fetch(:text)} " \

391 "(#{segment.fetch(:start)}-#{segment.fetch(:end)})"

392 )

393end

394```

395 

341```bash396```bash

342curl --request POST \397curl --request POST \

343 --url https://api.openai.com/v1/audio/transcriptions \398 --url https://api.openai.com/v1/audio/transcriptions \


421}476}

422```477```

423 478 

479```ruby

480require "openai"

481require "pathname"

482 

483client = OpenAI::Client.new

484audio = Pathname("german.wav")

485translation = client.audio.translations.create(file: audio, model: "whisper-1")

486puts(translation.text)

487```

488 

424```bash489```bash

425curl --request POST \490curl --request POST \

426 --url https://api.openai.com/v1/audio/translations \491 --url https://api.openai.com/v1/audio/translations \


521}586}

522```587```

523 588 

589```ruby

590require "openai"

591require "pathname"

592require "pp"

593 

594client = OpenAI::Client.new

595audio = Pathname("audio.wav")

596transcript = client.audio.transcriptions.create(

597 file: audio,

598 model: "whisper-1",

599 response_format: :verbose_json,

600 timestamp_granularities: [:word]

601)

602pp(transcript[:words])

603```

604 

524```bash605```bash

525curl https://api.openai.com/v1/audio/transcriptions \606curl https://api.openai.com/v1/audio/transcriptions \

526 -H "Authorization: Bearer $OPENAI_API_KEY" \607 -H "Authorization: Bearer $OPENAI_API_KEY" \


658}739}

659```740```

660 741 

742```ruby

743require "openai"

744require "pathname"

745 

746client = OpenAI::Client.new

747audio = Pathname("speech.wav")

748stream = client.audio.transcriptions.create_streaming(

749 file: audio,

750 model: "gpt-transcribe"

751)

752 

753stream.each { |event| puts(event.type) }

754```

755 

661```bash756```bash

662curl --request POST \757curl --request POST \

663 --url https://api.openai.com/v1/audio/transcriptions \758 --url https://api.openai.com/v1/audio/transcriptions \


768}863}

769```864```

770 865 

866```ruby

867require "openai"

868require "pathname"

869 

870client = OpenAI::Client.new

871audio = Pathname("speech.wav")

872transcript = client.audio.transcriptions.create(

873 file: audio,

874 model: "whisper-1",

875 prompt: "The speaker says OpenAI and Responses API"

876)

877puts(transcript.text)

878```

879 

771```bash880```bash

772curl --request POST \881curl --request POST \

773 --url https://api.openai.com/v1/audio/transcriptions \882 --url https://api.openai.com/v1/audio/transcriptions \


899}1008}

900```1009```

901 1010 

1011```ruby

1012require "openai"

1013require "pathname"

1014 

1015client = OpenAI::Client.new

1016audio = Pathname("speech.wav")

1017transcript = client.audio.transcriptions.create(

1018 file: audio,

1019 model: "gpt-4o-mini-transcribe"

1020)

1021 

1022response = client.responses.create(

1023 model: "gpt-4.1",

1024 input: "Add punctuation and paragraph breaks without changing the words:\n#{transcript.text}"

1025)

1026puts(response.output_text)

1027```

1028 

902 1029 

903A text model can correct misspellings and handle longer terminology lists than Whisper's 224-token prompt window. Evaluate corrections against the original audio to avoid changing what the speaker said.1030A text model can correct misspellings and handle longer terminology lists than Whisper's 224-token prompt window. Evaluate corrections against the original audio to avoid changing what the speaker said.

Details

156type StreamingEvent = responses.ResponseStreamEventUnion156type StreamingEvent = responses.ResponseStreamEventUnion

157```157```

158 158 

159```ruby

160require "openai"

161 

162client = OpenAI::Client.new

163stream = client.responses.stream(model: "gpt-5.5", input: "Say hello.")

164stream.each { |event| puts(event) }

165```

166 

159 167 

160 168 

161 169 

Details

124}124}

125```125```

126 126 

127```ruby

128require "openai"

129 

130client = OpenAI::Client.new

131event_schema = {

132 type: :object,

133 properties: {

134 name: {type: :string},

135 date: {type: :string},

136 participants: {type: :array, items: {type: :string}}

137 },

138 required: %w[name date participants],

139 additionalProperties: false

140}

141 

142response = client.responses.create(

143 model: "gpt-5.6",

144 input: [

145 {role: :system, content: "Extract the event information."},

146 {role: :user, content: "Alice and Bob are going to a science fair on Friday."}

147 ],

148 text: {

149 format: {

150 type: :json_schema,

151 name: "event",

152 strict: true,

153 schema: event_schema

154 }

155 }

156)

157 

158puts(response.output_text)

159```

160 

127 161 

128 162 

129### Supported models163### Supported models


335}369}

336```370```

337 371 

372```ruby

373require "openai"

374 

375client = OpenAI::Client.new

376step_schema = {

377 type: :object,

378 properties: {

379 explanation: {type: :string},

380 output: {type: :string}

381 },

382 required: %w[explanation output],

383 additionalProperties: false

384}

385math_schema = {

386 type: :object,

387 properties: {

388 steps: {type: :array, items: step_schema},

389 final_answer: {type: :string}

390 },

391 required: %w[steps final_answer],

392 additionalProperties: false

393}

394 

395response = client.responses.create(

396 model: "gpt-5.6",

397 input: [

398 {

399 role: :system,

400 content: "You are a helpful math tutor. Guide the user through the solution step by step."

401 },

402 {role: :user, content: "How can I solve 8x + 7 = -23?"}

403 ],

404 text: {

405 format: {

406 type: :json_schema,

407 name: "math_reasoning",

408 strict: true,

409 schema: math_schema

410 }

411 }

412)

413 

414puts(response.output_text)

415```

416 

338```bash417```bash

339curl https://api.openai.com/v1/responses \418curl https://api.openai.com/v1/responses \

340 -H "Authorization: Bearer $OPENAI_API_KEY" \419 -H "Authorization: Bearer $OPENAI_API_KEY" \


557}636}

558```637```

559 638 

639```ruby

640require "openai"

641 

642client = OpenAI::Client.new

643research_paper = <<~TEXT

644 Attention Is All You Need by Ashish Vaswani, Noam Shazeer, Niki Parmar,

645 Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Łukasz Kaiser, and Illia

646 Polosukhin. We propose the Transformer, a sequence transduction architecture

647 based entirely on attention. Keywords: transformers, attention, sequence

648 transduction.

649TEXT

650paper_schema = {

651 type: :object,

652 properties: {

653 title: {type: :string},

654 authors: {type: :array, items: {type: :string}},

655 abstract: {type: :string},

656 keywords: {type: :array, items: {type: :string}}

657 },

658 required: %w[title authors abstract keywords],

659 additionalProperties: false

660}

661 

662response = client.responses.create(

663 model: "gpt-5.6",

664 input: [

665 {

666 role: :system,

667 content: "Extract structured data from the supplied research paper text."

668 },

669 {role: :user, content: research_paper}

670 ],

671 text: {

672 format: {

673 type: :json_schema,

674 name: "research_paper_extraction",

675 strict: true,

676 schema: paper_schema

677 }

678 }

679)

680 

681puts(response.output_text)

682```

683 

560```bash684```bash

561curl https://api.openai.com/v1/responses \685curl https://api.openai.com/v1/responses \

562 -H "Authorization: Bearer $OPENAI_API_KEY" \686 -H "Authorization: Bearer $OPENAI_API_KEY" \


782}906}

783```907```

784 908 

909```ruby

910require "openai"

911 

912client = OpenAI::Client.new

913ui_schema = {

914 type: :object,

915 properties: {

916 type: {

917 type: :string,

918 enum: %w[div button header section field form]

919 },

920 label: {type: :string},

921 children: {type: :array, items: {"$ref" => "#"}},

922 attributes: {

923 type: :array,

924 items: {

925 type: :object,

926 properties: {

927 name: {type: :string},

928 value: {type: :string}

929 },

930 required: %w[name value],

931 additionalProperties: false

932 }

933 }

934 },

935 required: %w[type label children attributes],

936 additionalProperties: false

937}

938 

939response = client.responses.create(

940 model: "gpt-5.6",

941 input: [

942 {role: :system, content: "Convert the user request into a UI definition."},

943 {role: :user, content: "Make a user profile form."}

944 ],

945 text: {

946 format: {

947 type: :json_schema,

948 name: "ui",

949 description: "A dynamically generated UI",

950 strict: true,

951 schema: ui_schema

952 }

953 }

954)

955 

956puts(response.output_text)

957```

958 

785```bash959```bash

786curl https://api.openai.com/v1/responses \960curl https://api.openai.com/v1/responses \

787 -H "Authorization: Bearer $OPENAI_API_KEY" \961 -H "Authorization: Bearer $OPENAI_API_KEY" \


1064}1238}

1065```1239```

1066 1240 

1241```ruby

1242require "openai"

1243 

1244client = OpenAI::Client.new

1245compliance_schema = {

1246 type: :object,

1247 properties: {

1248 is_violating: {

1249 type: :boolean,

1250 description: "Whether the content violates the guidelines"

1251 },

1252 category: {

1253 type: %i[string null],

1254 enum: ["violence", "sexual", "self_harm", nil],

1255 description: "The violation category, or null when the content is allowed"

1256 },

1257 explanation_if_violating: {

1258 type: %i[string null],

1259 description: "Why the content violates the guidelines, or null"

1260 }

1261 },

1262 required: %w[is_violating category explanation_if_violating],

1263 additionalProperties: false

1264}

1265 

1266response = client.responses.create(

1267 model: "gpt-5.6",

1268 input: [

1269 {

1270 role: :system,

1271 content: "Determine whether the user input violates the guidelines and explain any violation."

1272 },

1273 {role: :user, content: "How do I prepare for a job interview?"}

1274 ],

1275 text: {

1276 format: {

1277 type: :json_schema,

1278 name: "content_compliance",

1279 description: "Determines whether content violates moderation rules",

1280 strict: true,

1281 schema: compliance_schema

1282 }

1283 }

1284)

1285 

1286puts(response.output_text)

1287```

1288 

1067```bash1289```bash

1068curl https://api.openai.com/v1/responses \1290curl https://api.openai.com/v1/responses \

1069 -H "Authorization: Bearer $OPENAI_API_KEY" \1291 -H "Authorization: Bearer $OPENAI_API_KEY" \


1300}1522}

1301```1523```

1302 1524 

1525```ruby

1526require "openai"

1527 

1528client = OpenAI::Client.new

1529math_schema = {

1530 type: :object,

1531 properties: {

1532 steps: {

1533 type: :array,

1534 items: {

1535 type: :object,

1536 properties: {

1537 explanation: {type: :string},

1538 output: {type: :string}

1539 },

1540 required: %w[explanation output],

1541 additionalProperties: false

1542 }

1543 },

1544 final_answer: {type: :string}

1545 },

1546 required: %w[steps final_answer],

1547 additionalProperties: false

1548}

1549 

1550response = client.responses.create(

1551 model: "gpt-5.6",

1552 input: [

1553 {

1554 role: :system,

1555 content: "You are a helpful math tutor. Guide the user through the solution step by step."

1556 },

1557 {role: :user, content: "How can I solve 8x + 7 = -23?"}

1558 ],

1559 text: {

1560 format: {

1561 type: :json_schema,

1562 name: "math_response",

1563 strict: true,

1564 schema: math_schema

1565 }

1566 }

1567)

1568 

1569puts(response.output_text)

1570```

1571 

1303```bash1572```bash

1304curl https://api.openai.com/v1/responses \1573curl https://api.openai.com/v1/responses \

1305 -H "Authorization: Bearer $OPENAI_API_KEY" \1574 -H "Authorization: Bearer $OPENAI_API_KEY" \


1572}1841}

1573```1842```

1574 1843 

1844```ruby

1845require "openai"

1846 

1847client = OpenAI::Client.new

1848step_schema = {

1849 type: :object,

1850 properties: {

1851 explanation: {type: :string},

1852 output: {type: :string}

1853 },

1854 required: %w[explanation output],

1855 additionalProperties: false

1856}

1857math_schema = {

1858 type: :object,

1859 properties: {

1860 steps: {type: :array, items: step_schema},

1861 final_answer: {type: :string}

1862 },

1863 required: %w[steps final_answer],

1864 additionalProperties: false

1865}

1866 

1867response = client.responses.create(

1868 model: "gpt-5.6",

1869 input: [

1870 {

1871 role: :system,

1872 content: "You are a helpful math tutor. Guide the user through the solution step by step."

1873 },

1874 {role: :user, content: "How can I solve 8x + 7 = -23?"}

1875 ],

1876 max_output_tokens: 1_024,

1877 text: {

1878 format: {

1879 type: :json_schema,

1880 name: "math_response",

1881 strict: true,

1882 schema: math_schema

1883 }

1884 }

1885)

1886 

1887if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE

1888 raise "Incomplete response"

1889end

1890 

1891message = response.output.find do |item|

1892 item.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)

1893end

1894unless message.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)

1895 raise "No response message"

1896end

1897 

1898content = message.content.fetch(0)

1899if content.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal)

1900 puts(content.refusal)

1901else

1902 puts(content.text)

1903end

1904```

1905 

1575 1906 

1576 1907 

1577 1908 


1735}2066}

1736```2067```

1737 2068 

2069```ruby

2070require "openai"

2071 

2072client = OpenAI::Client.new

2073math_schema = {

2074 type: :object,

2075 properties: {

2076 steps: {

2077 type: :array,

2078 items: {

2079 type: :object,

2080 properties: {

2081 explanation: {type: :string},

2082 output: {type: :string}

2083 },

2084 required: %w[explanation output],

2085 additionalProperties: false

2086 }

2087 },

2088 final_answer: {type: :string}

2089 },

2090 required: %w[steps final_answer],

2091 additionalProperties: false

2092}

2093 

2094response = client.responses.create(

2095 model: "gpt-5.6",

2096 input: [

2097 {

2098 role: :system,

2099 content: "You are a helpful math tutor. Guide the user through the solution step by step."

2100 },

2101 {role: :user, content: "How can I solve 8x + 7 = -23?"}

2102 ],

2103 text: {

2104 format: {

2105 type: :json_schema,

2106 name: "math_response",

2107 strict: true,

2108 schema: math_schema

2109 }

2110 }

2111)

2112 

2113response.output.each do |item|

2114 next unless item.is_a?(OpenAI::Models::Responses::ResponseOutputMessage)

2115 

2116 item.content.each do |content|

2117 case content

2118 when OpenAI::Models::Responses::ResponseOutputRefusal

2119 puts(content.refusal)

2120 when OpenAI::Models::Responses::ResponseOutputText

2121 puts(content.text)

2122 end

2123 end

2124end

2125```

2126 

1738 2127 

1739 2128 

1740The API response from a refusal will look something like this:2129The API response from a refusal will look something like this:


2596}2985}

2597```2986```

2598 2987 

2988```ruby

2989require "json"

2990require "openai"

2991 

2992client = OpenAI::Client.new

2993response = client.responses.create(

2994 model: "gpt-5.6",

2995 input: [

2996 {role: :system, content: "You are a helpful assistant designed to output JSON."},

2997 {

2998 role: :user,

2999 content: "Who won the World Series in 2020? Respond in the format {winner: ...}."

3000 }

3001 ],

3002 text: {format: {type: :json_object}}

3003)

3004 

3005if response.status == OpenAI::Responses::ResponseStatus::INCOMPLETE

3006 warn("The JSON response is incomplete.")

3007else

3008 refusal = response.output

3009 .grep(OpenAI::Models::Responses::ResponseOutputMessage)

3010 .flat_map(&:content)

3011 .find { |content| content.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal) }

3012 

3013 if refusal.is_a?(OpenAI::Models::Responses::ResponseOutputRefusal)

3014 puts(refusal.refusal)

3015 elsif response.status == OpenAI::Responses::ResponseStatus::COMPLETED

3016 puts(JSON.pretty_generate(JSON.parse(response.output_text)))

3017 end

3018end

3019```

3020 

2599## Resources3021## Resources

2600 3022 

2601To learn more about Structured Outputs, we recommend browsing the following resources:3023To learn more about Structured Outputs, we recommend browsing the following resources:

guides/text.md +30 −0

Details

242}242}

243```243```

244 244 

245```ruby

246require "openai"

247 

248client = OpenAI::Client.new

249response = client.responses.create(

250 model: "gpt-5.6",

251 instructions: "Talk like a pirate.",

252 reasoning: {effort: :low},

253 input: "Are semicolons optional in JavaScript?"

254)

255 

256puts(response.output_text)

257```

258 

245```bash259```bash

246curl "https://api.openai.com/v1/responses" \260curl "https://api.openai.com/v1/responses" \

247 -H "Content-Type: application/json" \261 -H "Content-Type: application/json" \


338}352}

339```353```

340 354 

355```ruby

356require "openai"

357 

358client = OpenAI::Client.new

359response = client.responses.create(

360 model: "gpt-5.6",

361 reasoning: {effort: :low},

362 input: [

363 {role: :developer, content: "Talk like a pirate."},

364 {role: :user, content: "Are semicolons optional in JavaScript?"}

365 ]

366)

367 

368puts(response.output_text)

369```

370 

341```bash371```bash

342curl "https://api.openai.com/v1/responses" \372curl "https://api.openai.com/v1/responses" \

343 -H "Content-Type: application/json" \373 -H "Content-Type: application/json" \

Details

98}98}

99```99```

100 100 

101```ruby

102require "openai"

103 

104client = OpenAI::Client.new

105audio = client.audio.speech.create(

106 model: "gpt-4o-mini-tts",

107 voice: "coral",

108 input: "Today is a wonderful day to build something people love!",

109 instructions: "Speak in a cheerful and positive tone."

110)

111File.binwrite("speech.mp3", audio.read)

112```

113 

101```bash114```bash

102curl https://api.openai.com/v1/audio/speech \115curl https://api.openai.com/v1/audio/speech \

103 -H "Authorization: Bearer $OPENAI_API_KEY" \116 -H "Authorization: Bearer $OPENAI_API_KEY" \


238}251}

239```252```

240 253 

254```ruby

255require "openai"

256 

257client = OpenAI::Client.new

258audio = client.audio.speech.create(

259 model: "gpt-4o-mini-tts",

260 voice: "alloy",

261 input: "Welcome to the OpenAI API.",

262 response_format: :pcm,

263 stream_format: :audio

264)

265while (chunk = audio.read(1_024))

266 puts(chunk.bytesize)

267end

268```

269 

241```bash270```bash

242curl https://api.openai.com/v1/audio/speech \271curl https://api.openai.com/v1/audio/speech \

243 -H "Authorization: Bearer $OPENAI_API_KEY" \272 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

75}75}

76```76```

77 77 

78```ruby

79require "openai"

80 

81client = OpenAI::Client.new

82 

83count = client.responses.input_tokens.count(

84 model: "gpt-5.6",

85 input: "Tell me a joke."

86)

87 

88puts(count.input_tokens)

89```

90 

78```bash91```bash

79curl https://api.openai.com/v1/responses/input_tokens \92curl https://api.openai.com/v1/responses/input_tokens \

80 -H "Authorization: Bearer $OPENAI_API_KEY" \93 -H "Authorization: Bearer $OPENAI_API_KEY" \


160}173}

161```174```

162 175 

176```ruby

177require "openai"

178 

179client = OpenAI::Client.new

180conversation = [

181 {role: :user, content: "What is 2 + 2?"},

182 {role: :assistant, content: "2 + 2 equals 4."},

183 {role: :user, content: "What about 3 + 3?"}

184]

185 

186count = client.responses.input_tokens.count(

187 model: "gpt-5.6",

188 input: conversation

189)

190 

191puts(count.input_tokens)

192```

193 

163```bash194```bash

164curl https://api.openai.com/v1/responses/input_tokens \195curl https://api.openai.com/v1/responses/input_tokens \

165 -H "Authorization: Bearer $OPENAI_API_KEY" \196 -H "Authorization: Bearer $OPENAI_API_KEY" \


246}277}

247```278```

248 279 

280```ruby

281require "openai"

282 

283client = OpenAI::Client.new

284 

285count = client.responses.input_tokens.count(

286 model: "gpt-5.6",

287 instructions: "You are a helpful assistant that explains concepts simply.",

288 input: "Explain quantum computing in one sentence."

289)

290 

291puts(count.input_tokens)

292```

293 

249```bash294```bash

250curl https://api.openai.com/v1/responses/input_tokens \295curl https://api.openai.com/v1/responses/input_tokens \

251 -H "Authorization: Bearer $OPENAI_API_KEY" \296 -H "Authorization: Bearer $OPENAI_API_KEY" \


356}401}

357```402```

358 403 

404```ruby

405require "openai"

406 

407client = OpenAI::Client.new

408 

409count = client.responses.input_tokens.count(

410 model: "gpt-5.6",

411 input: [

412 {

413 role: :user,

414 content: [

415 {

416 type: :input_image,

417 image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",

418 detail: :auto

419 },

420 {type: :input_text, text: "Summarize this chart."}

421 ]

422 }

423 ]

424)

425 

426puts(count.input_tokens)

427```

428 

359```bash429```bash

360curl https://api.openai.com/v1/responses/input_tokens \430curl https://api.openai.com/v1/responses/input_tokens \

361 -H "Authorization: Bearer $OPENAI_API_KEY" \431 -H "Authorization: Bearer $OPENAI_API_KEY" \


482}552}

483```553```

484 554 

555```ruby

556require "openai"

557 

558client = OpenAI::Client.new

559 

560count = client.responses.input_tokens.count(

561 model: "gpt-5.6",

562 input: "What is the weather in San Francisco?",

563 tools: [

564 {

565 type: :function,

566 name: "get_weather",

567 description: "Get the current weather in a location",

568 strict: true,

569 parameters: {

570 type: "object",

571 properties: {location: {type: "string"}},

572 required: ["location"],

573 additionalProperties: false

574 }

575 }

576 ]

577)

578 

579puts(count.input_tokens)

580```

581 

485```bash582```bash

486curl https://api.openai.com/v1/responses/input_tokens \583curl https://api.openai.com/v1/responses/input_tokens \

487 -H "Authorization: Bearer $OPENAI_API_KEY" \584 -H "Authorization: Bearer $OPENAI_API_KEY" \

guides/tools.md +43 −1

Details

386}386}

387```387```

388 388 

389```ruby

390require "openai"

391 

392client = OpenAI::Client.new

393parameters = {

394 type: :object,

395 properties: {customer_id: {type: :string}},

396 required: ["customer_id"],

397 additionalProperties: false

398}

399response = client.responses.create(

400 model: "gpt-5.6",

401 input: "List open orders for customer CUST-12345.",

402 parallel_tool_calls: false,

403 tools: [

404 {

405 type: :namespace,

406 name: "crm",

407 description: "CRM tools for customer lookup and order management.",

408 tools: [

409 {

410 type: :function,

411 name: "get_customer_profile",

412 description: "Fetch a customer profile by customer ID.",

413 parameters: parameters

414 },

415 {

416 type: :function,

417 name: "list_open_orders",

418 description: "List open orders for a customer ID.",

419 defer_loading: true,

420 parameters: parameters

421 }

422 ]

423 },

424 {type: :tool_search}

425 ]

426)

427 

428puts(response.output)

429```

430 

389 431

390 432 

391 433


590 tools: tools632 tools: tools

591)633)

592 634 

593puts(response.output.first.to_json)635puts(response.output.fetch(0).to_json)

594```636```

595 637 

596```bash638```bash

Details

106}106}

107```107```

108 108 

109```ruby

110require "openai"

111 

112client = OpenAI::Client.new

113response = client.responses.create(

114 model: "gpt-5.6",

115 input: "Rename fib() to fibonacci() in lib/fib.py and update run.py to use the new name.",

116 tools: [{type: :apply_patch}]

117)

118 

119patch_calls = response.output.select { |item| item.type == :apply_patch_call }

120puts(patch_calls)

121```

122 

109 123 

110**Example `apply_patch_call` object**124**Example `apply_patch_call` object**

111 125 


185}199}

186```200```

187 201 

202```ruby

203require "openai"

204 

205client = OpenAI::Client.new

206response_id = ENV.fetch("OPENAI_RESPONSE_ID")

207patch_call_id = ENV.fetch("OPENAI_APPLY_PATCH_CALL_ID")

208response = client.responses.create(

209 model: "gpt-5.6",

210 previous_response_id: response_id,

211 input: [{

212 type: :apply_patch_call_output,

213 call_id: patch_call_id,

214 status: :completed,

215 output: "Patch applied successfully."

216 }],

217 tools: [{type: :apply_patch}]

218)

219 

220puts(response.output_text)

221```

222 

188 223 

189If a patch fails (for example, file not found), set `status: "failed"` and include a helpful `output` string so the model can recover:224If a patch fails (for example, file not found), set `status: "failed"` and include a helpful `output` string so the model can recover:

190 225 

Details

104}104}

105```105```

106 106 

107```ruby

108require "openai"

109 

110client = OpenAI::Client.new

111 

112response = client.responses.create(

113 model: "gpt-5.6",

114 instructions: "You are a personal math tutor. Write and run Python code to answer each math question.",

115 input: "I need to solve the equation 3x + 11 = 14. Can you help me?",

116 tools: [

117 {

118 type: :code_interpreter,

119 container: {type: :auto, memory_limit: "4g"}

120 }

121 ]

122)

123 

124puts(response.output)

125```

126 

107 127 

108While we call this tool Code Interpreter, the model knows it as the "python128While we call this tool Code Interpreter, the model knows it as the "python

109 tool". Models usually understand prompts that refer to the code interpreter129 tool". Models usually understand prompts that refer to the code interpreter


226}246}

227```247```

228 248 

249```ruby

250require "openai"

251 

252client = OpenAI::Client.new

253container = client.containers.create(name: "analysis", memory_limit: "4g")

254response = client.responses.create(

255 model: "gpt-5.6",

256 tools: [{type: :code_interpreter, container: container.id}],

257 tool_choice: :required,

258 input: "Calculate 4 * 3.82, then take the square root twice."

259)

260puts(response.output_text)

261```

262 

229 263 

230You can choose from `1g` (default), `4g`, `16g`, or `64g`. Higher tiers offer more RAM for the session and are billed at the [built-in tools rates](https://developers.openai.com/api/docs/pricing#built-in-tools) for Code Interpreter. The selected `memory_limit` applies for the entire life of that container, whether it was created automatically or via the containers API.264You can choose from `1g` (default), `4g`, `16g`, or `64g`. Higher tiers offer more RAM for the session and are billed at the [built-in tools rates](https://developers.openai.com/api/docs/pricing#built-in-tools) for Code Interpreter. The selected `memory_limit` applies for the entire life of that container, whether it was created automatically or via the containers API.

231 265 

Details

275}275}

276```276```

277 277 

278```ruby

279require "openai"

280 

281client = OpenAI::Client.new

282response = client.responses.create(

283 model: "gpt-5.6",

284 input: "Open the Filters panel if needed, then search for penguin. Use the computer tool for UI interaction.",

285 tools: [{type: :computer}]

286)

287 

288puts(response.output)

289```

290 

278 291 

279The first turn often asks for a screenshot before the model commits to UI actions. That's normal.292The first turn often asks for a screenshot before the model commits to UI actions. That's normal.

280 293 


1698}1711}

1699```1712```

1700 1713 

1714```ruby

1715require "openai"

1716 

1717client = OpenAI::Client.new

1718response = client.responses.create(

1719 model: "gpt-5.6",

1720 previous_response_id: "resp_abc123",

1721 input: [{

1722 type: :computer_call_output,

1723 call_id: "call_abc123",

1724 output: {

1725 type: :computer_screenshot,

1726 image_url: "data:image/png;base64,<base64 bytes here>",

1727 detail: :original

1728 }

1729 }],

1730 tools: [{type: :computer}]

1731)

1732 

1733puts(response.output)

1734```

1735 

1701 1736 

1702### 5. Repeat until the tool stops calling1737### 5. Repeat until the tool stops calling

1703 1738 


2594}2629}

2595```2630```

2596 2631 

2632```ruby

2633require "openai"

2634 

2635client = OpenAI::Client.new

2636response = client.responses.create(

2637 model: "computer-use-preview",

2638 input: "Check whether the Filters panel is open.",

2639 truncation: :auto,

2640 tools: [{

2641 type: :computer_use_preview,

2642 display_width: 1024,

2643 display_height: 768,

2644 environment: :browser

2645 }]

2646)

2647 

2648puts(response.output)

2649```

2650 

2597 2651 

2598Keep the preview path only to maintain older integrations. For new implementations, use the GA flow described above.2652Keep the preview path only to maintain older integrations. For new implementations, use the GA flow described above.

2599 2653 

Details

312Console.WriteLine(response.GetOutputText());312Console.WriteLine(response.GetOutputText());

313```313```

314 314 

315```ruby

316require "openai"

317 

318client = OpenAI::Client.new

319response = client.responses.create(

320 model: "gpt-5.6",

321 input: "Summarize the Q2 earnings report.",

322 tools: [{

323 type: :mcp,

324 server_label: "Dropbox",

325 connector_id: "connector_dropbox",

326 authorization: "<oauth access token>",

327 require_approval: :never

328 }]

329)

330 

331puts(response.output_text)

332```

333 

315 334 

316 335 

317The API will return new items in the `output` array of the model response. If the model decides to use a Connector or MCP server, it will first make a request to list available tools from the server, which will create a `mcp_list_tools` output item. From the simple remote MCP server example above, it contains only one tool definition:336The API will return new items in the `output` array of the model response. If the model decides to use a Connector or MCP server, it will first make a request to list available tools from the server, which will create a `mcp_list_tools` output item. From the simple remote MCP server example above, it contains only one tool definition:


529Console.WriteLine(response.GetOutputText());548Console.WriteLine(response.GetOutputText());

530```549```

531 550 

551```ruby

552require "openai"

553 

554client = OpenAI::Client.new

555 

556response = client.responses.create(

557 model: "gpt-5.6",

558 input: "Roll 2d4+1",

559 tools: [

560 {

561 type: :mcp,

562 server_label: "dmcp",

563 server_description: "A Dungeons and Dragons MCP server to assist with dice rolling.",

564 server_url: "https://dmcp-server.deno.dev/mcp",

565 require_approval: :never,

566 allowed_tools: ["roll"]

567 }

568 ]

569)

570 

571puts(response.output_text)

572```

573 

532 574 

533### Step 2: Calling tools575### Step 2: Calling tools

534 576 


719Console.WriteLine(response2.GetOutputText());761Console.WriteLine(response2.GetOutputText());

720```762```

721 763 

764```ruby

765require "openai"

766 

767client = OpenAI::Client.new

768response = client.responses.create(

769 model: "gpt-5.6",

770 previous_response_id: "resp_682d498bdefc81918b4a6aa477bfafd904ad1e533afccbfa",

771 input: [{

772 type: :mcp_approval_response,

773 approval_request_id: "mcpr_682d498e3bd4819196a0ce1664f8e77b04ad1e533afccbfa",

774 approve: true

775 }],

776 tools: [{

777 type: :mcp,

778 server_label: "dmcp",

779 server_url: "https://dmcp-server.deno.dev/mcp",

780 server_description: "A Dungeons and Dragons MCP server.",

781 require_approval: :always

782 }]

783)

784 

785puts(response.output_text)

786```

787 

722 788 

723Here we're using the `previous_response_id` parameter to chain this new Response, with the previous Response that generated the approval request. But you can also pass back the [outputs from one response, as inputs into another](https://developers.openai.com/api/docs/guides/conversation-state#manually-manage-conversation-state) for maximum control over what enter's the model's context.789Here we're using the `previous_response_id` parameter to chain this new Response, with the previous Response that generated the approval request. But you can also pass back the [outputs from one response, as inputs into another](https://developers.openai.com/api/docs/guides/conversation-state#manually-manage-conversation-state) for maximum control over what enter's the model's context.

724 790 


863Console.WriteLine(response.GetOutputText());929Console.WriteLine(response.GetOutputText());

864```930```

865 931 

932```ruby

933require "openai"

934 

935client = OpenAI::Client.new

936 

937response = client.responses.create(

938 model: "gpt-5.6",

939 input: "What transport protocols does the 2025-03-26 version of the MCP spec support?",

940 tools: [

941 {

942 type: :mcp,

943 server_label: "deepwiki",

944 server_url: "https://mcp.deepwiki.com/mcp",

945 require_approval: {

946 never: {tool_names: ["ask_question", "read_wiki_structure"]}

947 }

948 }

949 ]

950)

951 

952puts(response.output_text)

953```

954 

866 955 

867## Authentication956## Authentication

868 957 


991Console.WriteLine(response.GetOutputText());1080Console.WriteLine(response.GetOutputText());

992```1081```

993 1082 

1083```ruby

1084require "openai"

1085 

1086client = OpenAI::Client.new

1087response = client.responses.create(

1088 model: "gpt-5.6",

1089 input: "Create a payment link for $20.",

1090 tools: [{

1091 type: :mcp,

1092 server_label: "stripe",

1093 server_url: "https://mcp.stripe.com",

1094 authorization: ENV.fetch("STRIPE_OAUTH_ACCESS_TOKEN")

1095 }]

1096)

1097 

1098puts(response.output_text)

1099```

1100 

994 1101 

995To prevent the leakage of sensitive tokens, the Responses API does not store the value you provide in the `authorization` field. This value will also not be visible in the Response object created. Because of this, you must send the `authorization` value in every Responses API creation request you make.1102To prevent the leakage of sensitive tokens, the Responses API does not store the value you provide in the `authorization` field. This value will also not be visible in the Response object created. Because of this, you must send the `authorization` value in every Responses API creation request you make.

996 1103 


1152Console.WriteLine(response.GetOutputText());1259Console.WriteLine(response.GetOutputText());

1153```1260```

1154 1261 

1262```ruby

1263require "openai"

1264 

1265client = OpenAI::Client.new

1266response = client.responses.create(

1267 model: "gpt-5.6",

1268 input: "What's on my Google Calendar for today?",

1269 tools: [{

1270 type: :mcp,

1271 server_label: "google_calendar",

1272 connector_id: "connector_googlecalendar",

1273 authorization: "<oauth access token>",

1274 require_approval: :never

1275 }]

1276)

1277 

1278puts(response.output_text)

1279```

1280 

1155 1281 

1156An MCP tool call from a Connector will look the same as an MCP tool call from a remote MCP server, using the `mcp_call` output item type. In this case, both the arguments to and the response from the Connector are JSON strings:1282An MCP tool call from a Connector will look the same as an MCP tool call from a remote MCP server, using the `mcp_call` output item type. In this case, both the arguments to and the response from the Connector are JSON strings:

1157 1283 

Details

108}108}

109```109```

110 110 

111```ruby

112require "base64"

113require "openai"

114 

115client = OpenAI::Client.new

116response = client.responses.create(

117 model: "gpt-5.6",

118 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

119 tools: [{type: :image_generation}]

120)

121 

122image_call = response.output.find do |item|

123 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

124end

125unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

126 raise "No image generation call returned"

127end

128 

129encoded_image = image_call.result or raise "No image returned"

130File.binwrite("otter.png", Base64.strict_decode64(encoded_image))

131```

132 

111 133 

112You can [provide input images](https://developers.openai.com/api/docs/guides/image-generation?image-generation-model=gpt-image#edit-images) using file IDs or base64 data.134You can [provide input images](https://developers.openai.com/api/docs/guides/image-generation?image-generation-model=gpt-image#edit-images) using file IDs or base64 data.

113 135 


312}334}

313```335```

314 336 

337```ruby

338require "base64"

339require "openai"

340 

341client = OpenAI::Client.new

342first = client.responses.create(

343 model: "gpt-5.6",

344 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

345 tools: [{type: :image_generation}]

346)

347 

348first_image = first.output.find do |item|

349 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

350end

351unless first_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

352 raise "No image generation call returned"

353end

354 

355encoded_image = first_image.result or raise "No image returned"

356File.binwrite("cat_and_otter.png", Base64.strict_decode64(encoded_image))

357 

358follow_up = client.responses.create(

359 model: "gpt-5.6",

360 input: "Now make it look realistic.",

361 previous_response_id: first.id,

362 tools: [{type: :image_generation}]

363)

364 

365follow_up_image = follow_up.output.find do |item|

366 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

367end

368unless follow_up_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

369 raise "No follow-up image generation call returned"

370end

371 

372encoded_image = follow_up_image.result or raise "No follow-up image returned"

373File.binwrite("cat_and_otter_realistic.png", Base64.strict_decode64(encoded_image))

374```

375 

315 376

316 377 

317 378


503}564}

504```565```

505 566 

567```ruby

568require "base64"

569require "openai"

570 

571client = OpenAI::Client.new

572first = client.responses.create(

573 model: "gpt-5.6",

574 input: "Generate an image of a gray tabby cat hugging an otter with an orange scarf.",

575 tools: [{type: :image_generation}]

576)

577 

578first_image = first.output.find do |item|

579 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

580end

581unless first_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

582 raise "No image generation call returned"

583end

584 

585encoded_image = first_image.result or raise "No image returned"

586File.binwrite("cat_and_otter.png", Base64.strict_decode64(encoded_image))

587 

588follow_up = client.responses.create(

589 model: "gpt-5.6",

590 input: [

591 {

592 role: :user,

593 content: [{type: :input_text, text: "Now make it look realistic."}]

594 },

595 {type: :image_generation_call, id: first_image.id}

596 ],

597 tools: [{type: :image_generation}]

598)

599 

600follow_up_image = follow_up.output.find do |item|

601 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

602end

603unless follow_up_image.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

604 raise "No follow-up image generation call returned"

605end

606 

607encoded_image = follow_up_image.result or raise "No follow-up image returned"

608File.binwrite("cat_and_otter_realistic.png", Base64.strict_decode64(encoded_image))

609```

610 

506 611 

507 612 

508## Streaming613## Streaming


634}739}

635```740```

636 741 

742```ruby

743require "base64"

744require "openai"

745 

746client = OpenAI::Client.new

747stream = client.responses.stream(

748 model: "gpt-5.6",

749 input: "Generate an image of a river made of white owl feathers.",

750 tools: [{type: :image_generation, partial_images: 2}]

751)

752 

753stream.each do |event|

754 case event

755 when OpenAI::Models::Responses::ResponseImageGenCallPartialImageEvent

756 image = Base64.strict_decode64(event.partial_image_b64)

757 File.binwrite("river-partial-#{event.partial_image_index}.png", image)

758 when OpenAI::Models::Responses::ResponseCompletedEvent

759 image_call = event.response.output.find do |item|

760 item.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

761 end

762 next unless image_call.is_a?(OpenAI::Models::Responses::ResponseOutputItem::ImageGenerationCall)

763 

764 File.binwrite(

765 "river-final.png",

766 Base64.strict_decode64(image_call.result)

767 )

768 end

769end

770```

771 

637 772 

638## Supported models773## Supported models

639 774 

Details

125}125}

126```126```

127 127 

128```ruby

129require "openai"

130 

131client = OpenAI::Client.new

132response = client.responses.create(

133 model: "gpt-5.6",

134 input: "Run ls -lah /mnt/data, then show the Python and Node.js versions.",

135 tools: [{type: :shell, environment: {type: :container_auto}}]

136)

137 

138puts(response.output_text)

139```

140 

128 141 

129## Hosted runtime details142## Hosted runtime details

130 143 


218}231}

219```232```

220 233 

234```ruby

235require "openai"

236 

237client = OpenAI::Client.new

238container = client.containers.create(name: "analysis", expires_after: {anchor: :last_active_at, minutes: 20})

239puts(container.id)

240```

241 

221 242 

222### 2. Reference the container in Responses243### 2. Reference the container in Responses

223 244 


310}331}

311```332```

312 333 

334```ruby

335require "openai"

336 

337client = OpenAI::Client.new

338response = client.responses.create(

339 model: "gpt-5.6",

340 input: "List files in the container and show disk usage.",

341 tools: [{

342 type: :shell,

343 environment: {type: :container_reference, container_id: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"}

344 }]

345)

346 

347puts(response.output_text)

348```

349 

313 350 

314## Attach skills351## Attach skills

315 352 


407}444}

408```445```

409 446 

447```ruby

448require "openai"

449 

450client = OpenAI::Client.new

451container = client.containers.create(

452 name: "skill-container",

453 skills: [

454 {type: :skill_reference, skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f"},

455 {

456 type: :skill_reference,

457 skill_id: "openai-spreadsheets",

458 version: "latest"

459 }

460 ]

461)

462 

463puts(container.id)

464```

465 

410 466 

411## Network access467## Network access

412 468 


547}603}

548```604```

549 605 

606```ruby

607require "openai"

608 

609client = OpenAI::Client.new

610response = client.responses.create(

611 model: "gpt-5.6",

612 input: "Fetch release pages and write /mnt/data/release_digest.md.",

613 tool_choice: :required,

614 tools: [{

615 type: :shell,

616 environment: {

617 type: :container_auto,

618 network_policy: {

619 type: :allowlist,

620 allowed_domains: ["pypi.org", "files.pythonhosted.org", "github.com"]

621 }

622 }

623 }]

624)

625 

626puts(response.output_text)

627```

628 

550 629 

551Allowlisting domains introduces security risks such as prompt630Allowlisting domains introduces security risks such as prompt

552 injection-driven data exfiltration. Only allowlist domains you trust and that631 injection-driven data exfiltration. Only allowlist domains you trust and that


809}888}

810```889```

811 890 

891```ruby

892require "openai"

893 

894client = OpenAI::Client.new

895client.containers.delete("container_id")

896puts("Deleted container_id")

897```

898 

812 899 

813## Domain secrets900## Domain secrets

814 901 


980}1067}

981```1068```

982 1069 

1070```ruby

1071require "openai"

1072 

1073client = OpenAI::Client.new

1074response = client.responses.create(

1075 model: "gpt-5.6",

1076 input: "Use curl to call https://httpbin.org/headers with an " \

1077 '"Authorization: Bearer $API_KEY" header.',

1078 tool_choice: :required,

1079 tools: [{

1080 type: :shell,

1081 environment: {

1082 type: :container_auto,

1083 network_policy: {

1084 type: :allowlist,

1085 allowed_domains: ["httpbin.org"],

1086 domain_secrets: [{

1087 domain: "httpbin.org",

1088 name: "API_KEY",

1089 value: "debug-secret-123"

1090 }]

1091 }

1092 }

1093 }]

1094)

1095 

1096puts(response.output_text)

1097```

1098 

983 1099 

984## Multi-turn workflows1100## Multi-turn workflows

985 1101 


1083}1199}

1084```1200```

1085 1201 

1202```ruby

1203require "openai"

1204 

1205client = OpenAI::Client.new

1206response = client.responses.create(

1207 model: "gpt-5.6",

1208 input: "Read /mnt/data/top5.csv and report the top candidate.",

1209 previous_response_id: "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",

1210 tools: [{

1211 type: :shell,

1212 environment: {type: :container_reference, container_id: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"}

1213 }]

1214)

1215 

1216puts(response.output_text)

1217```

1218 

1086 1219 

1087## Shell output in Responses1220## Shell output in Responses

1088 1221 


1186}1319}

1187```1320```

1188 1321 

1322```ruby

1323require "openai"

1324 

1325client = OpenAI::Client.new

1326response = client.responses.create(

1327 model: "gpt-5.6",

1328 instructions: "The local shell environment is macOS.",

1329 input: "Find the largest PDF in ~/Documents.",

1330 tools: [{type: :shell, environment: {type: :local}}]

1331)

1332 

1333puts(response.output)

1334```

1335 

1189 1336 

1190When you receive `shell_call` output items:1337When you receive `shell_call` output items:

1191 1338 


1315}1462}

1316```1463```

1317 1464 

1465```ruby

1466require "open3"

1467 

1468class ShellExecutor

1469 Result = Data.define(:stdout, :stderr, :exit_code, :timed_out)

1470 

1471 def initialize(default_timeout: 60)

1472 @default_timeout = default_timeout

1473 end

1474 

1475 def run(command, timeout: @default_timeout)

1476 Open3.popen3("sh", "-c", command, pgroup: true) do |stdin, stdout, stderr, wait_thread|

1477 stdin.close

1478 stdout_reader = Thread.new { stdout.read }

1479 stderr_reader = Thread.new { stderr.read }

1480 finished = wait_thread.join(timeout)

1481 terminate_process_group(wait_thread) unless finished

1482 

1483 Result.new(

1484 stdout: stdout_reader.value,

1485 stderr: stderr_reader.value,

1486 exit_code: wait_thread.value.exitstatus || -1,

1487 timed_out: finished.nil?

1488 )

1489 end

1490 end

1491 

1492 private

1493 

1494 def terminate_process_group(wait_thread)

1495 Process.kill("TERM", -wait_thread.pid)

1496 wait_thread.join(1)

1497 Process.kill("KILL", -wait_thread.pid)

1498 rescue Errno::ESRCH

1499 nil

1500 ensure

1501 wait_thread.join

1502 end

1503end

1504 

1505puts(ShellExecutor.new.run("printf shell-executor-ready"))

1506```

1507 

1318 1508 

1319Example shell_call_output payload1509Example shell_call_output payload

1320 1510 

Details

169}169}

170```170```

171 171 

172```ruby

173require "openai"

174 

175client = OpenAI::Client.new

176response = client.responses.create(

177 model: "gpt-5.6",

178 input: "Use the skills to add 144 and 377, then compute a triangle area with base 9 and height 13.",

179 tools: [{

180 type: :shell,

181 environment: {

182 type: :container_auto,

183 skills: [

184 {type: :skill_reference, skill_id: "<skill_id>"},

185 {type: :skill_reference, skill_id: "<skill_id>", version: "2"}

186 ]

187 }

188 }]

189)

190 

191puts(response.output_text)

192```

193 

172 194 

173### Prompting behavior195### Prompting behavior

174 196 


297}319}

298```320```

299 321 

322```ruby

323require "openai"

324 

325client = OpenAI::Client.new

326response = client.responses.create(

327 model: "gpt-5.6",

328 input: "Use the csv-insights skill to summarize today's CSV reports.",

329 tools: [{

330 type: :shell,

331 environment: {

332 type: :local,

333 skills: [{

334 name: "csv-insights",

335 description: "Summarize CSV files and produce a Markdown report.",

336 path: "<path-to-skill-folder>"

337 }]

338 }

339 }]

340)

341 

342puts(response.output_text)

343```

344 

300 345 

301## Skills in the user prompt346## Skills in the user prompt

302 347 

Details

103}103}

104```104```

105 105 

106```ruby

107require "openai"

108 

109client = OpenAI::Client.new

110video = client.videos.create(model: "sora-2", prompt: "A paper airplane flying over a forest")

111puts(video.id)

112```

113 

106```bash114```bash

107curl -X POST "https://api.openai.com/v1/videos" \115curl -X POST "https://api.openai.com/v1/videos" \

108 -H "Authorization: Bearer $OPENAI_API_KEY" \116 -H "Authorization: Bearer $OPENAI_API_KEY" \


251}259}

252```260```

253 261 

262```ruby

263require "openai"

264 

265client = OpenAI::Client.new

266video = client.videos.create(model: "sora-2", prompt: "A paper airplane flying over a forest")

267 

268while [:queued, :in_progress].include?(video.status)

269 sleep(2)

270 video = client.videos.retrieve(video.id)

271end

272 

273unless video.status == OpenAI::Models::Video::Status::COMPLETED

274 raise "Video creation failed. Status: #{video.status}"

275end

276 

277puts("Video successfully completed: #{video.id}")

278```

279 

254 280 

255Response example:281Response example:

256 282 


440}466}

441```467```

442 468 

469```ruby

470require "openai"

471 

472client = OpenAI::Client.new

473video = client.videos.create(

474 model: "sora-2",

475 prompt: "A video of the words 'Thank you' in sparkling letters"

476)

477pending_statuses = [

478 OpenAI::Models::Video::Status::QUEUED,

479 OpenAI::Models::Video::Status::IN_PROGRESS

480]

481while pending_statuses.include?(video.status)

482 sleep(2)

483 video = client.videos.retrieve(video.id)

484end

485raise "Video generation failed" if video.status == OpenAI::Models::Video::Status::FAILED

486 

487content = client.videos.download_content(video.id)

488File.binwrite("video.mp4", content.read)

489puts("Wrote video.mp4")

490```

491 

443```bash492```bash

444curl -L "https://api.openai.com/v1/videos/video_abc123/content" \493curl -L "https://api.openai.com/v1/videos/video_abc123/content" \

445 -H "Authorization: Bearer $OPENAI_API_KEY" \494 -H "Authorization: Bearer $OPENAI_API_KEY" \

Details

160}160}

161```161```

162 162 

163```ruby

164require "openai"

165 

166client = OpenAI::Client.new

167response = client.responses.create(

168 model: "gpt-5.6",

169 input: "Write a detailed market analysis.",

170 background: true

171)

172 

173puts(response.status)

174```

175 

163 176 

164In this guide, you will learn how to create webook endpoints in the dashboard, set up server-side code to handle them, and verify that inbound requests originated from OpenAI.177In this guide, you will learn how to create webook endpoints in the dashboard, set up server-side code to handle them, and verify that inbound requests originated from OpenAI.

165 178 

quickstart.md +3 −2

Details

923 923 

924```ruby924```ruby

925require "openai"925require "openai"

926require "pathname"

926 927 

927openai = OpenAI::Client.new928openai = OpenAI::Client.new

928 929 

929file = openai.files.create(930file = openai.files.create(

930 file: File.open("draconomicon.pdf", "rb"),931 file: Pathname("draconomicon.pdf"),

931 purpose: "user_data"932 purpose: "user_data"

932)933)

933 934 


1524 tools: tools1525 tools: tools

1525)1526)

1526 1527 

1527puts(response.output.first.to_json)1528puts(response.output.fetch(0).to_json)

1528```1529```

1529 1530 

1530```bash1531```bash