Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .castiron.stats.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
schema_version: 1
generation_id: c5512019-402c-4498-b28c-55fb7a36dc0e
openapi_spec_hash: 1faf0319c407c6534ef7c381614afbb6
openapi_transformed_spec_hash: 53eff50caa9d18046e4ff0615bc7512d
generation_id: f5bdc52b-495d-4bb5-b835-a2925f574dbc
openapi_spec_hash: 971c659b020aa37865787aa082cc4159
openapi_transformed_spec_hash: 75836bac7e1a2e2632c2709238aa355c
config_hash: 4617b0962f16d328804312ac81aac630
codegen_sha: dd4e5fa5e392402820c8ddebf0a66fedca7a4f5e
codegen_sha: 53a522327b03f11f80afbc2a00ae4c73ec5ccad4
38 changes: 0 additions & 38 deletions .github/workflows/ci-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,10 @@ on:
description: Runner label for CI jobs
required: true
type: string
publish-stainless-artifact:
description: Build and upload an installable Stainless artifact
required: true
type: boolean

permissions: {}

jobs:
stainless-artifact:
timeout-minutes: 10
name: stainless artifact
if: inputs.publish-stainless-artifact
permissions:
contents: read
id-token: write # Authenticate the artifact upload to pkg.stainless.com.
runs-on: ${{ inputs.runner }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Set up Ruby
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1
with:
bundler-cache: true

- name: Get GitHub OIDC token
id: github-oidc
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: core.setOutput('github_token', await core.getIDToken());

- name: Build and upload gem artifacts
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
SHA: ${{ github.sha }}
PACKAGE_NAME: openai
run: ./scripts/utils/upload-artifact.sh

lint:
timeout-minutes: 10
name: lint (rubocop)
Expand Down Expand Up @@ -159,7 +124,6 @@ jobs:
name: ci-required
# Keep branch protection on one stable context as the job matrix evolves.
needs:
- stainless-artifact
- lint
- typecheck
- validate-rbs
Expand All @@ -171,14 +135,12 @@ jobs:
steps:
- name: Check required job results
env:
ARTIFACT_RESULT: ${{ needs.stainless-artifact.result }}
LINT_RESULT: ${{ needs.lint.result }}
TYPECHECK_RESULT: ${{ needs.typecheck.result }}
RBS_VALIDATION_RESULT: ${{ needs.validate-rbs.result }}
PACKAGE_RESULT: ${{ needs.package.result }}
TEST_RESULT: ${{ needs.test-ruby.result }}
run: |
test "$ARTIFACT_RESULT" = "success" || test "$ARTIFACT_RESULT" = "skipped"
test "$LINT_RESULT" = "success"
test "$TYPECHECK_RESULT" = "success"
test "$RBS_VALIDATION_RESULT" = "success"
Expand Down
33 changes: 5 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
name: CI

# This workflow is shared by the Stainless staging repository and the OpenAI
# production repository. Stainless feature branches use push runs so they can
# publish installable artifacts; production feature branches use PR runs so a
# commit is validated only once.
on:
push:
branches:
- '**'
- '!gh-readonly-queue/**'
- '!integrated/**'
- '!stl-preview-head/**'
- '!stl-preview-base/**'
- '!generated'
- '!codegen/**'
- 'codegen/stl/**'
pull_request:
branches-ignore:
- 'stl-preview-head/**'
- 'stl-preview-base/**'
merge_group:
types:
- checks_requested
Expand All @@ -33,23 +21,12 @@ jobs:
checks:
name: ci
if: >-
(startsWith(github.repository, 'stainless-sdks/') &&
(github.event_name == 'push' || github.event.pull_request.head.repo.fork)) ||
(!startsWith(github.repository, 'stainless-sdks/') &&
(github.event_name == 'pull_request' ||
github.event_name == 'merge_group' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/next'))
github.event_name == 'pull_request' ||
github.event_name == 'merge_group' ||
github.ref == 'refs/heads/main' ||
github.ref == 'refs/heads/next'
permissions:
contents: read
id-token: write # Allow the called artifact job to mint its Stainless upload token.
uses: ./.github/workflows/ci-checks.yml
with:
runner: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
publish-stainless-artifact: >-
${{
github.repository == 'stainless-sdks/openai-ruby' &&
(github.event_name == 'push' || github.event.pull_request.head.repo.fork) &&
(github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') &&
!startsWith(github.ref, 'refs/heads/stl/')
}}
runner: ubuntu-latest
4 changes: 0 additions & 4 deletions .stats.yml

This file was deleted.

28 changes: 6 additions & 22 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,12 @@

## Reporting Security Issues

This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously and encourages you to report any security vulnerability promptly so that appropriate action can be taken.

To report a security issue, please contact the Stainless team at security@stainless.com.
Please report potential security vulnerabilities through OpenAI's
[coordinated vulnerability disclosure process](https://openai.com/policies/coordinated-vulnerability-disclosure-policy).
For questions about that process, contact disclosure@openai.com.

## Responsible Disclosure

We appreciate the efforts of security researchers and individuals who help us maintain the security of
SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible
disclosure practices by allowing us a reasonable amount of time to investigate and address the issue
before making any information public.

## Reporting Non-SDK Related Security Issues

If you encounter security issues that are not directly related to SDKs but pertain to the services
or products provided by OpenAI, please follow the respective company's security reporting guidelines.

### OpenAI Terms and Policies

Our Security Policy can be found at [Security Policy URL](https://openai.com/policies/coordinated-vulnerability-disclosure-policy).

Please contact disclosure@openai.com for any questions or concerns regarding the security of our services.

---

Thank you for helping us keep the SDKs and systems they interact with secure.
Please allow OpenAI a reasonable amount of time to investigate and address the
issue before making information public. Thank you for helping us keep this SDK
and the systems it interacts with secure.
1 change: 1 addition & 0 deletions api_reference/openapi.transformed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28325,6 +28325,7 @@ components:
- tenant.workload_identity.mapping.archived
- tenant.workload_identity.binding.created
- tenant.workload_identity.principal.provisioned
- tenant.workload_identity.access_token.issued
- tenant.admin_api_key.created
- tenant.admin_api_key.updated
- tenant.admin_api_key.deleted
Expand Down
4 changes: 3 additions & 1 deletion lib/openai/helpers/streaming/chat_completion_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ def parseable_input?

def model_dump(obj)
if obj.is_a?(OpenAI::Internal::Type::BaseModel)
obj.deep_to_h
# Streaming mutates typed nested accessors without replacing their raw values.
# Accumulate from those accessors so a later delta does not discard mutations.
OpenAI::Internal::Type::BaseModel.recursively_to_h(obj, convert: true)
elsif obj.respond_to?(:to_h)
obj.to_h
else
Expand Down
16 changes: 2 additions & 14 deletions lib/openai/helpers/streaming/response_stream.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,7 @@ def get_final_response
end

def get_output_text
response = get_final_response
text_parts = []

response.output.each do |output|
next unless output.type == :message

output.content.each do |content|
next unless content.type == :output_text
text_parts << content.text
end
end

text_parts.join
get_final_response.output_text
end

private
Expand All @@ -63,7 +51,7 @@ def iterator
@raw_stream.each do |raw_event|
events_to_yield = @state.handle_event(raw_event)
events_to_yield.each do |event|
if @starting_after.nil? || event.sequence_number > @starting_after
if @starting_after.nil? || event[:sequence_number] > @starting_after
y << event
end
end
Expand Down
80 changes: 64 additions & 16 deletions lib/openai/internal/type/base_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,19 @@ def fields
OpenAI::Internal::Type::Converter.coerce(target, value, state: state)
end
error = state.fetch(:error)
@coerced.store(name_sym, error || true)
stored =
case [target, error]
in [OpenAI::Internal::Type::Converter | Symbol, nil]
if value in ^target
value
else
coerced
end
else
converted =
if value in ^target
value
else
coerced
end
@data.store(name_sym, stored)
_store_field(
name_sym,
value,
converted: converted,
cache: error.nil? && target.is_a?(OpenAI::Internal::Type::Converter),
error: error
)
end

# rubocop:disable Style/CaseEquality
Expand All @@ -111,7 +111,7 @@ def fields

case @coerced[name_sym]
in true | false if OpenAI::Internal::Type::Converter === target
@data.fetch(name_sym)
@converted.fetch(name_sym)
Comment thread
jbeckwith-oai marked this conversation as resolved.
in ::StandardError => e
raise OpenAI::Errors::ConversionError.new(
on: self.class,
Expand Down Expand Up @@ -298,7 +298,6 @@ def coerce(value, state:)
keys = val.keys.to_set
instance = new
data = instance.to_h
viability = instance.instance_variable_get(:@coerced)

# rubocop:disable Metrics/BlockLength
error = state.fetch(:error)
Expand Down Expand Up @@ -336,8 +335,13 @@ def coerce(value, state:)
end

error ||= field_error
viability.store(name, field_error || true)
data.store(name, converted)
instance._store_field(
name,
item,
converted: converted,
cache: field_error.nil? && target.is_a?(OpenAI::Internal::Type::Converter),
error: field_error
)
end
# rubocop:enable Metrics/BlockLength

Expand All @@ -360,6 +364,7 @@ def dump(value, state:)
return super
end

model = value if value.is_a?(OpenAI::Internal::Type::BaseModel)
acc = {}

coerced.each do |key, val|
Expand All @@ -374,7 +379,8 @@ def dump(value, state:)
next
else
target = type_fn.call
acc.store(api_name, OpenAI::Internal::Type::Converter.dump(target, val, state: state))
item = model ? model._value_for_dump(name) : val
acc.store(api_name, OpenAI::Internal::Type::Converter.dump(target, item, state: state))
end
end
end
Expand Down Expand Up @@ -519,6 +525,47 @@ def to_yaml(*a) = OpenAI::Internal::Type::Converter.dump(self.class, self).to_ya
def encode_with(coder)
coder["data"] = @data
coder["coerced"] = @coerced
coder["converted"] = @converted
end

# Restores the converted cache while remaining compatible with YAML written by
# versions that stored converted values directly in data.
#
# @api private
#
# @param coder [Psych::Coder]
# @return [void]
def init_with(coder)
@data = coder["data"] || {}
@coerced = coder["coerced"] || {}
@converted = coder["converted"] || @data.dup
@last_response = nil
end

# @api private
#
# Returns the converted value used for request serialization without changing
# the raw value exposed by #[] and #to_h.
#
# @param name [Symbol]
# @return [Object]
def _value_for_dump(name) = @converted.fetch(name) { @data.fetch(name) }

# @api private
#
# Stores the raw field value separately from its converted accessor value.
#
# @param name [Symbol]
# @param value [Object]
# @param converted [Object]
# @param cache [Boolean]
# @param error [StandardError, nil]
#
# @return [Object]
def _store_field(name, value, converted:, cache:, error:)
@coerced.store(name, error || true)
cache ? @converted.store(name, converted) : @converted.delete(name)
@data.store(name, value)
Comment thread
jbeckwith-oai marked this conversation as resolved.
end

# Create a new instance of a model.
Expand All @@ -527,6 +574,7 @@ def encode_with(coder)
def initialize(data = {})
@data = {}
@coerced = {}
@converted = {}
@last_response = nil
OpenAI::Internal::Util.coerce_hash!(data).each do
if self.class.known_fields.key?(_1)
Expand Down
Loading