openai 0.99.0 → 0.101.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +1 -1
- data/bedrock.md +17 -1
- data/lib/openai/client.rb +13 -0
- data/lib/openai/helpers/agents/session_stream.rb +11 -36
- data/lib/openai/helpers/agents/tools.rb +34 -4
- data/lib/openai/helpers/beta/agents/creation_stream.rb +26 -0
- data/lib/openai/helpers/beta/agents/function_tool.rb +11 -4
- data/lib/openai/helpers/beta/agents/tool_dispatcher.rb +74 -0
- data/lib/openai/helpers/beta/agents/tool_error.rb +28 -0
- data/lib/openai/models/admin/organization/usage_audio_speeches_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_audio_transcriptions_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_code_interpreter_sessions_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_completions_params.rb +9 -4
- data/lib/openai/models/admin/organization/usage_completions_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_costs_params.rb +16 -4
- data/lib/openai/models/admin/organization/usage_costs_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_embeddings_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_file_search_calls_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_images_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_moderations_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_vector_stores_response.rb +125 -3
- data/lib/openai/models/admin/organization/usage_web_search_calls_params.rb +9 -4
- data/lib/openai/models/admin/organization/usage_web_search_calls_response.rb +125 -3
- data/lib/openai/models/beta/agents/environments/template_create_params.rb +6 -6
- data/lib/openai/models/beta/agents/environments/template_update_params.rb +3 -6
- data/lib/openai/models/beta/agents/sessions/turns/item_list_params.rb +79 -0
- data/lib/openai/models/beta/beta_response_computer_tool_call_output_item.rb +2 -2
- data/lib/openai/models/beta/beta_response_error.rb +12 -1
- data/lib/openai/models/beta/beta_response_tool_search_output_item_param.rb +1166 -3
- data/lib/openai/models/beta/beta_responses_server_event.rb +12 -1
- data/lib/openai/models/beta/beta_tool.rb +12 -9
- data/lib/openai/models/beta/beta_tool_search_output_namespace_tool.rb +176 -0
- data/lib/openai/models/beta/environment_param.rb +6 -6
- data/lib/openai/models/beta/session_turn_error.rb +9 -0
- data/lib/openai/models/chat/chat_completion_chunk.rb +85 -18
- data/lib/openai/models/decision.rb +313 -0
- data/lib/openai/models/decision_create_params.rb +233 -0
- data/lib/openai/models/decision_input_image.rb +53 -0
- data/lib/openai/models/decision_input_message.rb +60 -0
- data/lib/openai/models/decision_input_part.rb +20 -0
- data/lib/openai/models/decision_input_text.rb +21 -0
- data/lib/openai/models/error_object.rb +12 -1
- data/lib/openai/models/eval_create_params.rb +1 -1
- data/lib/openai/models/eval_create_response.rb +1 -1
- data/lib/openai/models/eval_list_response.rb +1 -1
- data/lib/openai/models/eval_retrieve_response.rb +1 -1
- data/lib/openai/models/eval_update_response.rb +1 -1
- data/lib/openai/models/fine_tuning/job_list_params.rb +14 -4
- data/lib/openai/models/graders/score_model_grader.rb +2 -2
- data/lib/openai/models/image_edit_params.rb +12 -9
- data/lib/openai/models/realtime/realtime_client_event.rb +9 -0
- data/lib/openai/models/realtime/session_update_event.rb +16 -0
- data/lib/openai/models/responses/response_computer_tool_call_output_item.rb +2 -2
- data/lib/openai/models/responses/response_error.rb +12 -1
- data/lib/openai/models/responses/response_tool_search_output_item_param.rb +1166 -3
- data/lib/openai/models/responses/responses_server_event.rb +12 -1
- data/lib/openai/models/responses/tool.rb +12 -9
- data/lib/openai/models/responses/tool_search_output_namespace_tool.rb +174 -0
- data/lib/openai/models/video_create_error.rb +12 -1
- data/lib/openai/models.rb +12 -0
- data/lib/openai/providers/bedrock.rb +20 -1
- data/lib/openai/resources/admin/organization/usage.rb +15 -6
- data/lib/openai/resources/beta/agents/environments/templates.rb +3 -4
- data/lib/openai/resources/beta/agents/sessions/turns/items.rb +68 -0
- data/lib/openai/resources/beta/agents/sessions/turns.rb +4 -0
- data/lib/openai/resources/beta/agents/sessions.rb +22 -2
- data/lib/openai/resources/decisions.rb +59 -0
- data/lib/openai/resources/fine_tuning/jobs.rb +7 -2
- data/lib/openai/resources/images.rb +8 -6
- data/lib/openai/version.rb +1 -1
- data/lib/openai.rb +11 -0
- data/rbi/openai/client.rbi +3 -0
- data/rbi/openai/helpers/agents.rbi +2 -0
- data/rbi/openai/helpers/beta/agents/function_tool.rbi +8 -3
- data/rbi/openai/helpers/beta/agents/tool_error.rbi +19 -0
- data/rbi/openai/helpers/beta/agents.rbi +12 -0
- data/rbi/openai/models/admin/organization/usage_audio_speeches_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_audio_transcriptions_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_code_interpreter_sessions_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_completions_params.rbi +9 -4
- data/rbi/openai/models/admin/organization/usage_completions_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_costs_params.rbi +16 -4
- data/rbi/openai/models/admin/organization/usage_costs_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_embeddings_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_file_search_calls_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_images_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_moderations_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_vector_stores_response.rbi +194 -1
- data/rbi/openai/models/admin/organization/usage_web_search_calls_params.rbi +12 -4
- data/rbi/openai/models/admin/organization/usage_web_search_calls_response.rbi +194 -1
- data/rbi/openai/models/beta/agents/environments/template_create_params.rbi +6 -6
- data/rbi/openai/models/beta/agents/environments/template_update_params.rbi +3 -6
- data/rbi/openai/models/beta/agents/sessions/turns/item_list_params.rbi +139 -0
- data/rbi/openai/models/beta/beta_response_computer_tool_call_output_item.rbi +2 -2
- data/rbi/openai/models/beta/beta_response_error.rbi +12 -0
- data/rbi/openai/models/beta/beta_response_tool_search_output_item_param.rbi +1893 -18
- data/rbi/openai/models/beta/beta_responses_server_event.rbi +12 -0
- data/rbi/openai/models/beta/beta_tool.rbi +12 -9
- data/rbi/openai/models/beta/beta_tool_search_output_namespace_tool.rbi +272 -0
- data/rbi/openai/models/beta/environment_param.rbi +6 -6
- data/rbi/openai/models/beta/session_turn_error.rbi +18 -0
- data/rbi/openai/models/chat/chat_completion_chunk.rbi +123 -17
- data/rbi/openai/models/decision.rbi +586 -0
- data/rbi/openai/models/decision_create_params.rbi +435 -0
- data/rbi/openai/models/decision_input_image.rbi +81 -0
- data/rbi/openai/models/decision_input_message.rbi +96 -0
- data/rbi/openai/models/decision_input_part.rbi +24 -0
- data/rbi/openai/models/decision_input_text.rbi +49 -0
- data/rbi/openai/models/error_object.rbi +12 -0
- data/rbi/openai/models/eval_create_params.rbi +1 -1
- data/rbi/openai/models/eval_create_response.rbi +1 -1
- data/rbi/openai/models/eval_list_response.rbi +1 -1
- data/rbi/openai/models/eval_retrieve_response.rbi +1 -1
- data/rbi/openai/models/eval_update_response.rbi +1 -1
- data/rbi/openai/models/fine_tuning/job_list_params.rbi +14 -4
- data/rbi/openai/models/graders/score_model_grader.rbi +2 -2
- data/rbi/openai/models/image_edit_params.rbi +12 -9
- data/rbi/openai/models/realtime/session_update_event.rbi +16 -0
- data/rbi/openai/models/responses/response_computer_tool_call_output_item.rbi +2 -2
- data/rbi/openai/models/responses/response_error.rbi +12 -0
- data/rbi/openai/models/responses/response_tool_search_output_item_param.rbi +1901 -18
- data/rbi/openai/models/responses/responses_server_event.rbi +12 -0
- data/rbi/openai/models/responses/tool.rbi +12 -9
- data/rbi/openai/models/responses/tool_search_output_namespace_tool.rbi +272 -0
- data/rbi/openai/models/video_create_error.rbi +12 -0
- data/rbi/openai/models.rbi +12 -0
- data/rbi/openai/resources/admin/organization/usage.rbi +15 -6
- data/rbi/openai/resources/beta/agents/environments/templates.rbi +3 -4
- data/rbi/openai/resources/beta/agents/sessions/turns/items.rbi +62 -0
- data/rbi/openai/resources/beta/agents/sessions/turns.rbi +3 -0
- data/rbi/openai/resources/beta/agents/sessions.rbi +2 -0
- data/rbi/openai/resources/decisions.rbi +57 -0
- data/rbi/openai/resources/fine_tuning/jobs.rbi +7 -2
- data/rbi/openai/resources/images.rbi +8 -6
- data/sig/openai/client.rbs +2 -0
- data/sig/openai/helpers/agents.rbs +3 -0
- data/sig/openai/helpers/beta/agents/function_tool.rbs +5 -2
- data/sig/openai/helpers/beta/agents/tool_error.rbs +17 -0
- data/sig/openai/helpers/beta/agents.rbs +5 -0
- data/sig/openai/models/admin/organization/usage_audio_speeches_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_audio_transcriptions_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_code_interpreter_sessions_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_completions_params.rbs +14 -6
- data/sig/openai/models/admin/organization/usage_completions_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_costs_params.rbs +25 -7
- data/sig/openai/models/admin/organization/usage_costs_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_embeddings_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_file_search_calls_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_images_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_moderations_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_vector_stores_response.rbs +87 -2
- data/sig/openai/models/admin/organization/usage_web_search_calls_params.rbs +19 -7
- data/sig/openai/models/admin/organization/usage_web_search_calls_response.rbs +87 -2
- data/sig/openai/models/beta/agents/environments/template_create_params.rbs +4 -4
- data/sig/openai/models/beta/agents/environments/template_update_params.rbs +2 -4
- data/sig/openai/models/beta/agents/sessions/turns/item_list_params.rbs +91 -0
- data/sig/openai/models/beta/beta_response_computer_tool_call_output_item.rbs +2 -2
- data/sig/openai/models/beta/beta_response_error.rbs +10 -0
- data/sig/openai/models/beta/beta_response_tool_search_output_item_param.rbs +993 -4
- data/sig/openai/models/beta/beta_responses_server_event.rbs +10 -0
- data/sig/openai/models/beta/beta_tool.rbs +8 -6
- data/sig/openai/models/beta/beta_tool_search_output_namespace_tool.rbs +162 -0
- data/sig/openai/models/beta/environment_param.rbs +4 -4
- data/sig/openai/models/beta/session_turn_error.rbs +12 -0
- data/sig/openai/models/chat/chat_completion_chunk.rbs +96 -12
- data/sig/openai/models/decision.rbs +296 -0
- data/sig/openai/models/decision_create_params.rbs +227 -0
- data/sig/openai/models/decision_input_image.rbs +51 -0
- data/sig/openai/models/decision_input_message.rbs +57 -0
- data/sig/openai/models/decision_input_part.rbs +12 -0
- data/sig/openai/models/decision_input_text.rbs +15 -0
- data/sig/openai/models/error_object.rbs +10 -0
- data/sig/openai/models/eval_create_params.rbs +1 -1
- data/sig/openai/models/eval_create_response.rbs +1 -1
- data/sig/openai/models/eval_list_response.rbs +1 -1
- data/sig/openai/models/eval_retrieve_response.rbs +1 -1
- data/sig/openai/models/eval_update_response.rbs +1 -1
- data/sig/openai/models/fine_tuning/job_list_params.rbs +14 -4
- data/sig/openai/models/graders/score_model_grader.rbs +3 -3
- data/sig/openai/models/image_edit_params.rbs +8 -6
- data/sig/openai/models/responses/response_computer_tool_call_output_item.rbs +2 -2
- data/sig/openai/models/responses/response_error.rbs +10 -0
- data/sig/openai/models/responses/response_tool_search_output_item_param.rbs +993 -4
- data/sig/openai/models/responses/responses_server_event.rbs +10 -0
- data/sig/openai/models/responses/tool.rbs +8 -6
- data/sig/openai/models/responses/tool_search_output_namespace_tool.rbs +160 -0
- data/sig/openai/models/video_create_error.rbs +10 -0
- data/sig/openai/models.rbs +12 -0
- data/sig/openai/resources/beta/agents/sessions/turns/items.rbs +24 -0
- data/sig/openai/resources/beta/agents/sessions/turns.rbs +2 -0
- data/sig/openai/resources/beta/agents/sessions.rbs +1 -0
- data/sig/openai/resources/decisions.rbs +15 -0
- metadata +38 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7c9c92914efc09920f412b87f40bd0401a68b41f69fa4ffcaee090cf8ee93959
|
|
4
|
+
data.tar.gz: af39812b8849fa3bdb1f0f04dd5da8368c45b244ec24c52cfe901e5e22445690
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 49f421e6b6fca640e3abbee1028b7df1935c9cc7c79ddecebc6fb50b01e920ca5fc0cbed0b652cc065730b5e6696f0de18367d51e0f4fa0ceec8caee92ccdcf5
|
|
7
|
+
data.tar.gz: ae6558f4994712ecb02afe85d5961c26657bc48001ad4c8dde460f408b256434cf741a71f60bb17432e3c35d2dca4180d81a8b77ceafdc6831a8117ff7971116
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.101.0](https://github.com/openai/openai-ruby/compare/v0.100.0...v0.101.0) (2026-10-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **api:** add standalone Decisions support ([#811](https://github.com/openai/openai-ruby/issues/811)) ([ab10fa3](https://github.com/openai/openai-ruby/commit/ab10fa3742cde6fe968d13099917c2c6282bd76d))
|
|
9
|
+
|
|
10
|
+
## [0.100.0](https://github.com/openai/openai-ruby/compare/v0.99.0...v0.100.0) (2026-10-06)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **agents:** handle local tools during streaming creation ([#805](https://github.com/openai/openai-ruby/issues/805)) ([a961bd6](https://github.com/openai/openai-ruby/commit/a961bd6aea012b8c1d47c84ac6b950142fd45470))
|
|
16
|
+
* **agents:** support tool search (defer_loading=true) in typed function tools ([#809](https://github.com/openai/openai-ruby/issues/809)) ([389fd0b](https://github.com/openai/openai-ruby/commit/389fd0b67186c625fd19a324412ae3166db5a1c6))
|
|
17
|
+
* **api:** add agent turn items and usage source grouping ([#810](https://github.com/openai/openai-ruby/issues/810)) ([606902b](https://github.com/openai/openai-ruby/commit/606902b255cd095fe3530fbe620edfe4b7210ab3))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* select the Mantle inference path for GPT-6.1 Sol ([#808](https://github.com/openai/openai-ruby/issues/808)) ([133bea0](https://github.com/openai/openai-ruby/commit/133bea01973fd3e6d195392891e732b2c07cdfd3))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Chores
|
|
26
|
+
|
|
27
|
+
* **deps-dev:** bump sorbet-runtime from 0.6.13506 to 0.6.13508 in the development-dependencies group ([#804](https://github.com/openai/openai-ruby/issues/804)) ([5bd0b99](https://github.com/openai/openai-ruby/commit/5bd0b99725e29d2646dcfdb5d41b9efba0955f99))
|
|
28
|
+
|
|
3
29
|
## [0.99.0](https://github.com/openai/openai-ruby/compare/v0.98.0...v0.99.0) (2026-10-02)
|
|
4
30
|
|
|
5
31
|
|
data/README.md
CHANGED
data/bedrock.md
CHANGED
|
@@ -17,7 +17,23 @@ response = client.responses.create(
|
|
|
17
17
|
puts(response.output_text)
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The provider uses `https://bedrock-mantle.<region>.api.aws/v1` by default
|
|
20
|
+
The provider uses `https://bedrock-mantle.<region>.api.aws/v1` by default. AWS documents this route for [GPT OSS](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-openai-gpt-oss-120b.html), including Responses and Chat Completions, and for model discovery.
|
|
21
|
+
|
|
22
|
+
When no base URL override is configured, Responses and Chat Completions creation requests whose final structured request body specifies exactly `model: "openai.gpt-6.1-sol"` use `/openai/v1/responses` and `/openai/v1/chat/completions`, respectively, as required by the [GPT-6.1 Sol model card](https://docs.aws.amazon.com/bedrock/latest/userguide/model-card-openai-gpt-6-1-sol.html). **Sol on Mantle requires `region: "us-east-1"`; it is not available in the `us-west-2` region used in the general example above.** String and Ruby symbol model IDs are supported. This selection happens before bearer authentication or SigV4 signing. It does not change the client's base URL or infer routes for other model names.
|
|
23
|
+
|
|
24
|
+
Calls without a structured model field, including pre-encoded/streaming request bodies and retrieving or deleting a response, use the configured base URL. For Sol response follow-ups, use a client explicitly configured with the Sol API root:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
sol_client = OpenAI::Client.new(
|
|
28
|
+
provider: OpenAI::Providers.bedrock(
|
|
29
|
+
region: "us-east-1",
|
|
30
|
+
base_url: "https://bedrock-mantle.us-east-1.api.aws/openai/v1"
|
|
31
|
+
)
|
|
32
|
+
)
|
|
33
|
+
response = sol_client.responses.retrieve("resp_example")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Explicit `base_url` and `AWS_BEDROCK_BASE_URL` overrides are used as configured for every model. AWS controls which endpoints and features are supported; unsupported calls surface as normal API errors.
|
|
21
37
|
|
|
22
38
|
## Bedrock Runtime
|
|
23
39
|
|
data/lib/openai/client.rb
CHANGED
|
@@ -40,6 +40,9 @@ module OpenAI
|
|
|
40
40
|
# @api private
|
|
41
41
|
attr_reader :workload_identity_auth
|
|
42
42
|
|
|
43
|
+
# @return [OpenAI::Resources::Decisions]
|
|
44
|
+
attr_reader :decisions
|
|
45
|
+
|
|
43
46
|
# Given a prompt, the model will return one or more predicted completions, and can
|
|
44
47
|
# also return the probabilities of alternative tokens at each position.
|
|
45
48
|
# @return [OpenAI::Resources::Completions]
|
|
@@ -195,6 +198,15 @@ module OpenAI
|
|
|
195
198
|
|
|
196
199
|
# @api private
|
|
197
200
|
private def build_request(request, options)
|
|
201
|
+
if @provider_runtime
|
|
202
|
+
built = super
|
|
203
|
+
body = built[:body]
|
|
204
|
+
# Capture only the final model; provider hooks run after body encoding.
|
|
205
|
+
model = body.reverse_each.find { |key, _| key == :model || key == "model" }&.last if body.is_a?(Hash)
|
|
206
|
+
model = model.to_s if model.is_a?(Symbol)
|
|
207
|
+
return built.merge(provider_request_model: model)
|
|
208
|
+
end
|
|
209
|
+
|
|
198
210
|
unless @workload_identity_auth && x509_transport?(@requester)
|
|
199
211
|
return super
|
|
200
212
|
end
|
|
@@ -803,6 +815,7 @@ module OpenAI
|
|
|
803
815
|
on_retry: self.on_retry()
|
|
804
816
|
)
|
|
805
817
|
|
|
818
|
+
@decisions = OpenAI::Resources::Decisions.new(client: self)
|
|
806
819
|
@completions = OpenAI::Resources::Completions.new(client: self)
|
|
807
820
|
@chat = OpenAI::Resources::Chat.new(client: self)
|
|
808
821
|
@embeddings = OpenAI::Resources::Embeddings.new(client: self)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
3
|
+
require_relative "../beta/agents/tool_dispatcher"
|
|
4
4
|
require_relative "../beta/agents/result"
|
|
5
5
|
|
|
6
6
|
module OpenAI
|
|
@@ -19,6 +19,7 @@ module OpenAI
|
|
|
19
19
|
session_id:,
|
|
20
20
|
input:,
|
|
21
21
|
tool_handlers: {},
|
|
22
|
+
on_tool_error: nil,
|
|
22
23
|
idempotency_key: nil,
|
|
23
24
|
output_type: nil,
|
|
24
25
|
request_options: {}
|
|
@@ -46,7 +47,13 @@ module OpenAI
|
|
|
46
47
|
|
|
47
48
|
@options[:extra_headers] = headers
|
|
48
49
|
@recent_events = {}
|
|
49
|
-
@
|
|
50
|
+
@dispatcher = OpenAI::Helpers::Beta::Agents::ToolDispatcher.new(
|
|
51
|
+
sessions: sessions,
|
|
52
|
+
session_id: session_id,
|
|
53
|
+
tool_handlers: @handlers,
|
|
54
|
+
on_tool_error: on_tool_error,
|
|
55
|
+
request_options: @options
|
|
56
|
+
)
|
|
50
57
|
@closed = false
|
|
51
58
|
session = @sessions.retrieve(@session_id, request_options: @options)
|
|
52
59
|
unless session.status == :idle
|
|
@@ -154,12 +161,12 @@ module OpenAI
|
|
|
154
161
|
|
|
155
162
|
terminal = event.type == :"agent.session.failed" ||
|
|
156
163
|
(event.type == :"agent.session.idle" && @turn_ended)
|
|
157
|
-
invocation = prepare_call(event) unless terminal
|
|
164
|
+
invocation = @dispatcher.prepare_call(event) unless terminal
|
|
158
165
|
close if terminal
|
|
159
166
|
yielder << event
|
|
160
167
|
break if terminal || @closed
|
|
161
168
|
|
|
162
|
-
dispatch(invocation.call) if invocation
|
|
169
|
+
@dispatcher.dispatch(invocation.call) if invocation
|
|
163
170
|
end
|
|
164
171
|
|
|
165
172
|
raise RuntimeError, "Session event stream ended before the turn reached idle or failed" unless @closed
|
|
@@ -187,38 +194,6 @@ module OpenAI
|
|
|
187
194
|
true
|
|
188
195
|
end
|
|
189
196
|
|
|
190
|
-
def prepare_call(event)
|
|
191
|
-
unless event.type == :"agent.session.turn.item.added" &&
|
|
192
|
-
event.item.is_a?(OpenAI::Models::Beta::AgentFunctionCallItem)
|
|
193
|
-
return
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
call = event.item
|
|
197
|
-
key = [call.turn_id.dup, call.call_id.dup]
|
|
198
|
-
return if @handled_calls.key?(key)
|
|
199
|
-
|
|
200
|
-
@handled_calls[key] = true
|
|
201
|
-
handler = @handlers[call.name]
|
|
202
|
-
return unless handler
|
|
203
|
-
|
|
204
|
-
Tools.prepare(call, handler)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def dispatch(result)
|
|
208
|
-
idempotency_key = SecureRandom.uuid
|
|
209
|
-
delays = [0.1, 0.3, 0.6]
|
|
210
|
-
begin
|
|
211
|
-
@sessions
|
|
212
|
-
.events
|
|
213
|
-
.create(@session_id, events: [result], idempotency_key: idempotency_key, request_options: @options)
|
|
214
|
-
rescue OpenAI::Errors::BadRequestError => error
|
|
215
|
-
delay = delays.shift
|
|
216
|
-
raise unless delay && Tools.pending_call_race?(error, result[:call_id])
|
|
217
|
-
|
|
218
|
-
sleep(delay)
|
|
219
|
-
retry
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
197
|
end
|
|
223
198
|
end
|
|
224
199
|
end
|
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "../beta/agents/tool_error"
|
|
4
|
+
|
|
3
5
|
module OpenAI
|
|
4
6
|
module Helpers
|
|
5
7
|
module Agents
|
|
6
8
|
# @api private
|
|
7
9
|
module Tools
|
|
10
|
+
# @api private
|
|
11
|
+
module TypedHandler
|
|
12
|
+
end
|
|
13
|
+
|
|
8
14
|
# Capture routing and detached arguments before caller code sees the event,
|
|
9
15
|
# but defer the application callback until iteration resumes after yielding it.
|
|
10
|
-
def self.prepare(call, handler)
|
|
16
|
+
def self.prepare(call, handler, session_id:, on_tool_error: nil)
|
|
11
17
|
base = {type: :"agent.session.input.tool_result", turn_id: call.turn_id.dup, call_id: call.call_id.dup}
|
|
18
|
+
tool_name = call.name.dup
|
|
19
|
+
arguments_error = nil
|
|
12
20
|
arguments = begin
|
|
13
21
|
JSON.parse(call.arguments.is_a?(String) ? call.arguments : JSON.generate(call.arguments))
|
|
14
|
-
rescue StandardError
|
|
22
|
+
rescue StandardError => error
|
|
23
|
+
arguments_error = error
|
|
15
24
|
nil
|
|
16
25
|
end
|
|
17
26
|
|
|
18
27
|
lambda do
|
|
28
|
+
stage = :arguments
|
|
19
29
|
begin
|
|
30
|
+
raise arguments_error if arguments_error
|
|
20
31
|
raise ArgumentError, "Function arguments must be a JSON object" unless arguments.is_a?(Hash)
|
|
21
32
|
|
|
22
|
-
|
|
33
|
+
stage = :execution
|
|
34
|
+
report_stage = -> (value) { stage = value } if on_tool_error && handler.is_a?(TypedHandler)
|
|
35
|
+
output = handler.call(arguments, &report_stage)
|
|
36
|
+
stage = :output
|
|
23
37
|
output = JSON.generate(output) if output.is_a?(Hash)
|
|
24
38
|
unless output.nil? || output.is_a?(String) || output.is_a?(Array)
|
|
25
39
|
raise ArgumentError, "Tool output must be a string, object, content array, or nil"
|
|
@@ -31,7 +45,23 @@ module OpenAI
|
|
|
31
45
|
end
|
|
32
46
|
|
|
33
47
|
base.merge(success: true, output: output)
|
|
34
|
-
rescue StandardError
|
|
48
|
+
rescue StandardError => error
|
|
49
|
+
if on_tool_error
|
|
50
|
+
failure = OpenAI::Helpers::Beta::Agents::ToolError.new(
|
|
51
|
+
error: error,
|
|
52
|
+
tool_name: tool_name,
|
|
53
|
+
session_id: session_id,
|
|
54
|
+
turn_id: base[:turn_id],
|
|
55
|
+
call_id: base[:call_id],
|
|
56
|
+
stage: stage
|
|
57
|
+
)
|
|
58
|
+
begin
|
|
59
|
+
on_tool_error.call(failure)
|
|
60
|
+
rescue StandardError
|
|
61
|
+
# Diagnostics must not prevent submission of the original failure.
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
35
65
|
base.merge(success: false, error: "Tool handler failed.")
|
|
36
66
|
end
|
|
37
67
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "result"
|
|
4
|
+
require_relative "tool_dispatcher"
|
|
4
5
|
|
|
5
6
|
module OpenAI
|
|
6
7
|
module Helpers
|
|
@@ -46,6 +47,22 @@ module OpenAI
|
|
|
46
47
|
self
|
|
47
48
|
end
|
|
48
49
|
|
|
50
|
+
# @api private
|
|
51
|
+
def configure_tool_handlers(sessions:, tool_handlers:, request_options:)
|
|
52
|
+
@dispatcher = ToolDispatcher.new(
|
|
53
|
+
sessions: sessions,
|
|
54
|
+
tool_handlers: tool_handlers,
|
|
55
|
+
request_options: request_options
|
|
56
|
+
)
|
|
57
|
+
@collector = ResultCollector.new(handler_names: @dispatcher.handler_names)
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def close
|
|
62
|
+
@closed = true
|
|
63
|
+
super
|
|
64
|
+
end
|
|
65
|
+
|
|
49
66
|
private
|
|
50
67
|
|
|
51
68
|
def iterator
|
|
@@ -53,8 +70,17 @@ module OpenAI
|
|
|
53
70
|
source = super
|
|
54
71
|
@iterator = OpenAI::Internal::Util.chain_fused(source) do |yielder|
|
|
55
72
|
source.each do |event|
|
|
73
|
+
invocation = nil
|
|
74
|
+
if @dispatcher && event.is_a?(OpenAI::Internal::Type::BaseModel)
|
|
75
|
+
@dispatcher.observe(event)
|
|
76
|
+
invocation = @dispatcher.prepare_call(event)
|
|
77
|
+
end
|
|
78
|
+
|
|
56
79
|
@collector.observe(event)
|
|
57
80
|
yielder << event
|
|
81
|
+
break if @closed
|
|
82
|
+
|
|
83
|
+
@dispatcher.dispatch(invocation.call) if invocation
|
|
58
84
|
end
|
|
59
85
|
|
|
60
86
|
rescue StandardError => error
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "model_adapter"
|
|
4
|
+
require_relative "../../agents/tools"
|
|
4
5
|
|
|
5
6
|
module OpenAI
|
|
6
7
|
module Helpers
|
|
@@ -14,8 +15,9 @@ module OpenAI
|
|
|
14
15
|
# @param name [String]
|
|
15
16
|
# @param arguments [Class<OpenAI::BaseModel>]
|
|
16
17
|
# @param description [String]
|
|
18
|
+
# @param defer_loading [Boolean, nil] Load this tool through hosted tool search; nil leaves the setting omitted.
|
|
17
19
|
# @yieldparam arguments [OpenAI::BaseModel]
|
|
18
|
-
def initialize(name:, arguments:, description: "", &handler)
|
|
20
|
+
def initialize(name:, arguments:, description: "", defer_loading: nil, &handler)
|
|
19
21
|
ModelAdapter.validate!(arguments, parameter: "arguments")
|
|
20
22
|
|
|
21
23
|
raise ArgumentError, "a callback is required" unless handler
|
|
@@ -29,7 +31,8 @@ module OpenAI
|
|
|
29
31
|
type: :function,
|
|
30
32
|
name: @name,
|
|
31
33
|
parameters: arguments.to_json_schema,
|
|
32
|
-
description: description
|
|
34
|
+
description: description,
|
|
35
|
+
**(defer_loading.nil? ? {} : {defer_loading: defer_loading})
|
|
33
36
|
)
|
|
34
37
|
.freeze
|
|
35
38
|
end
|
|
@@ -40,7 +43,9 @@ module OpenAI
|
|
|
40
43
|
|
|
41
44
|
# Pass these local bindings to sessions.stream(tool_handlers: ...).
|
|
42
45
|
# @return [Hash{String=>Proc}]
|
|
43
|
-
def handlers
|
|
46
|
+
def handlers
|
|
47
|
+
{name => method(:call).to_proc.extend(OpenAI::Helpers::Agents::Tools::TypedHandler)}
|
|
48
|
+
end
|
|
44
49
|
|
|
45
50
|
# Parse using the SDK's BaseModel conventions, then invoke the callback.
|
|
46
51
|
# This is not JSON Schema validation; validate application constraints
|
|
@@ -48,6 +53,8 @@ module OpenAI
|
|
|
48
53
|
# @param arguments [Hash{String=>Object}, String]
|
|
49
54
|
# @return [Object]
|
|
50
55
|
def call(arguments)
|
|
56
|
+
# The dispatcher supplies this internal stage reporter only when observing errors.
|
|
57
|
+
yield :arguments if block_given?
|
|
51
58
|
values = JSON.parse(arguments.is_a?(String) ? arguments : JSON.generate(arguments), symbolize_names: true)
|
|
52
59
|
raise ArgumentError, "Tool arguments must be a JSON object" unless values.is_a?(Hash)
|
|
53
60
|
parsed = ModelAdapter.coerce(@arguments, values)
|
|
@@ -55,9 +62,9 @@ module OpenAI
|
|
|
55
62
|
raise ArgumentError, "Tool arguments cannot be parsed into the argument model"
|
|
56
63
|
end
|
|
57
64
|
|
|
65
|
+
yield :execution if block_given?
|
|
58
66
|
@handler.call(parsed)
|
|
59
67
|
end
|
|
60
|
-
|
|
61
68
|
end
|
|
62
69
|
end
|
|
63
70
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../agents/tools"
|
|
4
|
+
|
|
5
|
+
module OpenAI
|
|
6
|
+
module Helpers
|
|
7
|
+
module Beta
|
|
8
|
+
module Agents
|
|
9
|
+
# @api private
|
|
10
|
+
# Shared callback preparation, deduplication, and tool-result submission.
|
|
11
|
+
class ToolDispatcher
|
|
12
|
+
def initialize(sessions:, tool_handlers:, request_options:, session_id: nil, on_tool_error: nil)
|
|
13
|
+
@sessions = sessions
|
|
14
|
+
@session_id = session_id
|
|
15
|
+
@handlers = tool_handlers.to_h.dup
|
|
16
|
+
@on_tool_error = on_tool_error
|
|
17
|
+
@handled_calls = {}
|
|
18
|
+
@options = request_options.to_h.dup
|
|
19
|
+
@options.delete(:idempotency_key)
|
|
20
|
+
headers = {"OpenAI-Beta" => "agents=v1"}.merge(@options[:extra_headers].to_h)
|
|
21
|
+
@options[:extra_headers] = headers.reject do |key, _|
|
|
22
|
+
key.to_s.casecmp?("idempotency-key")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def handler_names = @handlers.keys
|
|
27
|
+
|
|
28
|
+
def observe(event)
|
|
29
|
+
@session_id ||= event.session.id.dup if event.type == :"agent.session.created"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def prepare_call(event)
|
|
33
|
+
unless event.type == :"agent.session.turn.item.added" &&
|
|
34
|
+
event.item.is_a?(OpenAI::Models::Beta::AgentFunctionCallItem)
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
call = event.item
|
|
39
|
+
key = [call.turn_id.dup, call.call_id.dup]
|
|
40
|
+
return if @handled_calls.key?(key)
|
|
41
|
+
|
|
42
|
+
@handled_calls[key] = true
|
|
43
|
+
handler = @handlers[call.name]
|
|
44
|
+
return unless handler
|
|
45
|
+
raise RuntimeError, "Creation stream did not identify a session" unless @session_id
|
|
46
|
+
|
|
47
|
+
OpenAI::Helpers::Agents::Tools.prepare(
|
|
48
|
+
call,
|
|
49
|
+
handler,
|
|
50
|
+
session_id: @session_id,
|
|
51
|
+
on_tool_error: @on_tool_error
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def dispatch(result)
|
|
56
|
+
idempotency_key = SecureRandom.uuid
|
|
57
|
+
delays = [0.1, 0.3, 0.6]
|
|
58
|
+
begin
|
|
59
|
+
@sessions
|
|
60
|
+
.events
|
|
61
|
+
.create(@session_id, events: [result], idempotency_key: idempotency_key, request_options: @options)
|
|
62
|
+
rescue OpenAI::Errors::BadRequestError => error
|
|
63
|
+
delay = delays.shift
|
|
64
|
+
raise unless delay && OpenAI::Helpers::Agents::Tools.pending_call_race?(error, result[:call_id])
|
|
65
|
+
|
|
66
|
+
sleep(delay)
|
|
67
|
+
retry
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenAI
|
|
4
|
+
module Helpers
|
|
5
|
+
module Beta
|
|
6
|
+
module Agents
|
|
7
|
+
# Beta, local-only diagnostic delivered to sessions.stream(on_tool_error:).
|
|
8
|
+
# Use alongside tool_handlers for logging or monitoring argument parsing,
|
|
9
|
+
# handler execution, and output conversion failures, not API/transport errors.
|
|
10
|
+
# The original exception may contain sensitive application data.
|
|
11
|
+
class ToolError
|
|
12
|
+
attr_reader :error, :tool_name, :session_id, :turn_id, :call_id, :stage
|
|
13
|
+
|
|
14
|
+
# @api private
|
|
15
|
+
def initialize(error:, tool_name:, session_id:, turn_id:, call_id:, stage:)
|
|
16
|
+
@error = error
|
|
17
|
+
@tool_name = tool_name.dup.freeze
|
|
18
|
+
@session_id = session_id.dup.freeze
|
|
19
|
+
@turn_id = turn_id.dup.freeze
|
|
20
|
+
@call_id = call_id.dup.freeze
|
|
21
|
+
@stage = stage
|
|
22
|
+
freeze
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|