Skip to content

Commit 9e236ff

Browse files
authored
Merge pull request #574 from simonx1/add-responses-endpoint
Add new Responses API endpoint
2 parents e8b12a5 + d2fc6c3 commit 9e236ff

8 files changed

+958
-0
lines changed

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Stream text with GPT-4, transcribe and translate audio with Whisper, or create i
3838
- [Streaming Chat](#streaming-chat)
3939
- [Vision](#vision)
4040
- [JSON Mode](#json-mode)
41+
- [Responses API](#responses-api)
4142
- [Functions](#functions)
4243
- [Completions](#completions)
4344
- [Embeddings](#embeddings)
@@ -464,6 +465,74 @@ You can stream it as well!
464465
# }
465466
```
466467

468+
### Responses API
469+
OpenAI's most advanced interface for generating model responses. Supports text and image inputs, and text outputs. Create stateful interactions with the model, using the output of previous responses as input. Extend the model's capabilities with built-in tools for file search, web search, computer use, and more. Allow the model access to external systems and data using function calling.
470+
471+
```ruby
472+
response = client.responses(parameters: {
473+
model: "gpt-4o",
474+
input: "Hello!"
475+
})
476+
477+
puts response.dig("output", 0, "content", 0, "text")
478+
```
479+
#### Follow-up Messages (former threads functionality available in the Assistant API)
480+
```ruby
481+
followup = client.responses(parameters: {
482+
model: "gpt-4o",
483+
input: "Remind me, what is my name?",
484+
previous_response_id: response["id"]
485+
})
486+
487+
puts followup.dig("output", 0, "content", 0, "text")
488+
```
489+
490+
#### Tool Calls
491+
```ruby
492+
response = client.responses(parameters: {
493+
model: "gpt-4o",
494+
input: "What's the weather in Paris?",
495+
tools: [
496+
{
497+
"type" => "function",
498+
"name" => "get_current_weather",
499+
"description" => "Get the current weather in a given location",
500+
"parameters" => {
501+
"type" => "object",
502+
"properties" => {
503+
"location" => {
504+
"type" => "string",
505+
"description" => "The geographic location to get the weather for"
506+
}
507+
},
508+
"required" => ["location"]
509+
}
510+
}
511+
]
512+
})
513+
514+
puts response.dig("output", 0, "name") # => "get_current_weather"
515+
```
516+
517+
#### Streaming
518+
```ruby
519+
chunks = []
520+
streamer = proc { |chunk, _| chunks << chunk }
521+
522+
client.responses(parameters: {
523+
model: "gpt-4o",
524+
input: "Hello!",
525+
stream: streamer
526+
})
527+
528+
output = chunks
529+
.select { |c| c["type"] == "response.output_text.delta" }
530+
.map { |c| c["delta"] }
531+
.join
532+
533+
puts output
534+
```
535+
467536
### Functions
468537

469538
You can describe and pass in functions and the model will intelligently choose to output a JSON object containing arguments to call them - eg., to use your method `get_current_weather` to get the weather in a given location. Note that tool_choice is optional, but if you exclude it, the model will choose whether to use the function or not ([see here](https://platform.openai.com/docs/api-reference/chat/create#chat-create-tool_choice)).

lib/openai/client.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def completions(parameters: {})
3232
json_post(path: "/completions", parameters: parameters)
3333
end
3434

35+
def responses(parameters: {})
36+
json_post(path: "/responses", parameters: parameters)
37+
end
38+
3539
def audio
3640
@audio ||= OpenAI::Audio.new(client: self)
3741
end

spec/fixtures/cassettes/gpt-4o_responsesapi_responses.yml

Lines changed: 119 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
http_interactions:
3+
- request:
4+
method: post
5+
uri: https://api.openai.com/v1/responses
6+
body:
7+
encoding: UTF-8
8+
string: '{"model":"gpt-4o","input":"Hello!","stream":true}'
9+
headers:
10+
Content-Type:
11+
- application/json
12+
Authorization:
13+
- Bearer <OPENAI_ACCESS_TOKEN>
14+
Accept-Encoding:
15+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16+
Accept:
17+
- "*/*"
18+
User-Agent:
19+
- Ruby
20+
response:
21+
status:
22+
code: 200
23+
message: OK
24+
headers:
25+
Date:
26+
- Wed, 12 Mar 2025 16:59:40 GMT
27+
Content-Type:
28+
- text/event-stream; charset=utf-8
29+
Transfer-Encoding:
30+
- chunked
31+
Connection:
32+
- keep-alive
33+
Openai-Version:
34+
- '2020-10-01'
35+
Openai-Organization:
36+
- tropic-7
37+
X-Request-Id:
38+
- req_fa50380d9311693c3f763a22b24eee77
39+
Openai-Processing-Ms:
40+
- '51'
41+
Strict-Transport-Security:
42+
- max-age=31536000; includeSubDomains; preload
43+
Cf-Cache-Status:
44+
- DYNAMIC
45+
Set-Cookie:
46+
- __cf_bm=IY3ThYrVK7alqLEMbB1twLEG88Bef1OUz6pWWgkYrfE-1741798780-1.0.1.1-s5avIb8RUXCHgZmfvWToJkH_uELi5H6BS0QtoSVSISmg9.RBA7Z97ySYNXZ6Czt7RZnT.K6Pj9W5u3NDNf6u4rroFm_BAWRyUaZUHgbnkR0;
47+
path=/; expires=Wed, 12-Mar-25 17:29:40 GMT; domain=.api.openai.com; HttpOnly;
48+
Secure; SameSite=None
49+
- _cfuvid=tjwk_Z09jnlOWbISJrfgtJrv.wn3k_50UJ9uEAnlEU0-1741798780709-0.0.1.1-604800000;
50+
path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None
51+
X-Content-Type-Options:
52+
- nosniff
53+
Server:
54+
- cloudflare
55+
Cf-Ray:
56+
- 91f4d7e9c902b1b8-WAW
57+
Alt-Svc:
58+
- h3=":443"; ma=86400
59+
body:
60+
encoding: UTF-8
61+
string: |+
62+
event: response.created
63+
data: {"type":"response.created","response":{"id":"resp_67d1bd7c931c8191870ad798c711562004d0a3fcf4e20298","object":"response","created_at":1741798780,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[],"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
64+
65+
event: response.in_progress
66+
data: {"type":"response.in_progress","response":{"id":"resp_67d1bd7c931c8191870ad798c711562004d0a3fcf4e20298","object":"response","created_at":1741798780,"status":"in_progress","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[],"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}}}
67+
68+
event: response.output_item.added
69+
data: {"type":"response.output_item.added","output_index":0,"item":{"type":"message","id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","status":"in_progress","role":"assistant","content":[]}}
70+
71+
event: response.content_part.added
72+
data: {"type":"response.content_part.added","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"part":{"type":"output_text","text":"","annotations":[]}}
73+
74+
event: response.output_text.delta
75+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":"Hi"}
76+
77+
event: response.output_text.delta
78+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" there"}
79+
80+
event: response.output_text.delta
81+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":"!"}
82+
83+
event: response.output_text.delta
84+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" How"}
85+
86+
event: response.output_text.delta
87+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" can"}
88+
89+
event: response.output_text.delta
90+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" I"}
91+
92+
event: response.output_text.delta
93+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" assist"}
94+
95+
event: response.output_text.delta
96+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" you"}
97+
98+
event: response.output_text.delta
99+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":" today"}
100+
101+
event: response.output_text.delta
102+
data: {"type":"response.output_text.delta","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"delta":"?"}
103+
104+
event: response.output_text.done
105+
data: {"type":"response.output_text.done","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"text":"Hi there! How can I assist you today?"}
106+
107+
event: response.content_part.done
108+
data: {"type":"response.content_part.done","item_id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","output_index":0,"content_index":0,"part":{"type":"output_text","text":"Hi there! How can I assist you today?","annotations":[]}}
109+
110+
event: response.output_item.done
111+
data: {"type":"response.output_item.done","output_index":0,"item":{"type":"message","id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Hi there! How can I assist you today?","annotations":[]}]}}
112+
113+
event: response.completed
114+
data: {"type":"response.completed","response":{"id":"resp_67d1bd7c931c8191870ad798c711562004d0a3fcf4e20298","object":"response","created_at":1741798780,"status":"completed","error":null,"incomplete_details":null,"instructions":null,"max_output_tokens":null,"model":"gpt-4o-2024-08-06","output":[{"type":"message","id":"msg_67d1bd7ce24c819188993565819babf404d0a3fcf4e20298","status":"completed","role":"assistant","content":[{"type":"output_text","text":"Hi there! How can I assist you today?","annotations":[]}]}],"parallel_tool_calls":true,"previous_response_id":null,"reasoning":{"effort":null,"generate_summary":null},"store":true,"temperature":1.0,"text":{"format":{"type":"text"}},"tool_choice":"auto","tools":[],"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":27,"input_tokens_details":{"cached_tokens":0},"output_tokens":11,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":38},"user":null,"metadata":{}}}
115+
116+
recorded_at: Wed, 12 Mar 2025 16:59:41 GMT
117+
recorded_with: VCR 6.1.0
118+
...

0 commit comments

Comments
 (0)