From 1ffb80f8ab469895ce62ddb1b70adb98b2d60909 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 15:15:34 -0700 Subject: [PATCH 01/23] Consolidate and harden CI workflows --- .github/workflows/ci.yml | 189 +++++++----------- .github/workflows/codeql.yml | 17 +- .github/workflows/create-releases.yml | 79 ++------ .github/workflows/detect-breaking-changes.yml | 43 ---- .github/workflows/examples.yml | 42 ++++ .../workflows/publish-sonatype-reusable.yml | 90 +++++++++ .github/workflows/publish-sonatype.yml | 68 +------ scripts/detect-breaking-changes | 18 +- 8 files changed, 241 insertions(+), 305 deletions(-) delete mode 100644 .github/workflows/detect-breaking-changes.yml create mode 100644 .github/workflows/examples.yml create mode 100644 .github/workflows/publish-sonatype-reusable.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16ffe1b3e..f03681b43 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,28 +1,27 @@ name: CI + on: push: branches: - - '**' - - '!integrated/**' - - '!stl-preview-head/**' - - '!stl-preview-base/**' - - '!generated' - - '!codegen/**' - - 'codegen/stl/**' + - main + - next pull_request: - branches-ignore: - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - main + - next permissions: contents: read +concurrency: + group: ci-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: lint: + name: CI / lint + runs-on: ubuntu-24.04 timeout-minutes: 15 - name: lint - runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -36,24 +35,17 @@ jobs: java-version: | 8 21 - cache: gradle - name: Set up Gradle - uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Run lints run: ./scripts/lint build: + name: CI / build + Jackson compatibility + runs-on: ubuntu-24.04 timeout-minutes: 30 - name: build - runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: |- - (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && - (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') && - !(github.repository == 'stainless-sdks/openai-java' && - github.event_name == 'push' && - !startsWith(github.ref, 'refs/heads/stl/')) steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -67,29 +59,19 @@ jobs: java-version: | 8 21 - cache: gradle - name: Set up Gradle - uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - - name: Build SDK - # disable gradle daemon in CI because it is flakey + - name: Build SDK and run compatibility tests env: - GRADLE_OPTS: "-Dkotlin.compiler.execution.strategy=in-process" + GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process run: ./scripts/build - upload-maven-artifacts: + test: + name: CI / tests + runs-on: ubuntu-24.04 timeout-minutes: 30 - name: build-and-upload-maven-artifacts - permissions: - contents: read - id-token: write - runs-on: depot-ubuntu-24.04 - if: |- - github.repository == 'stainless-sdks/openai-java' && - github.event_name == 'push' && - github.event.head_commit.message != 'codegen metadata' && - !startsWith(github.ref, 'refs/heads/stl/') steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 @@ -103,67 +85,23 @@ jobs: java-version: | 8 21 - cache: gradle - name: Set up Gradle - uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - - name: Build SDK - # disable gradle daemon in CI because it is flakey - env: - GRADLE_OPTS: "-Dkotlin.compiler.execution.strategy=in-process" - run: ./scripts/build + - name: Run tests + run: ./scripts/test - - name: Upload Maven artifacts - env: - URL: https://pkg.stainless.com/s - SHA: ${{ github.sha }} - PROJECT: openai-java - run: | - set -euo pipefail + api_compatibility: + name: CI / API compatibility + if: github.event_name == 'pull_request' + runs-on: ubuntu-24.04 + timeout-minutes: 20 - max_retries=5 - attempt=1 - - while true; do - echo "Maven artifact upload attempt ${attempt}/${max_retries}" - - oidc_response="$(curl -sSf \ - -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ - "${ACTIONS_ID_TOKEN_REQUEST_URL}")" - github_token="$(printf '%s' "$oidc_response" | jq -er '.value')" - - upload_log="$(mktemp)" - set +e - AUTH="$github_token" ./scripts/upload-artifacts 2>&1 | tee "$upload_log" - upload_status=${PIPESTATUS[0]} - set -e - - if [ "$upload_status" -eq 0 ]; then - break - fi - - if [ "$attempt" -lt "$max_retries" ] && \ - grep -q "Failed to get valid signed URL" "$upload_log" && \ - grep -q "GitHub JWT is missing or invalid\\." "$upload_log"; then - sleep_seconds=$((3 * (1 << (attempt - 1)))) - echo "Retrying after fresh OIDC token due to transient GitHub JWT validation failure" - echo "Sleeping ${sleep_seconds}s before retry" - sleep "$sleep_seconds" - attempt=$((attempt + 1)) - continue - fi - - exit "$upload_status" - done - test: - timeout-minutes: 30 - name: test - runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: + fetch-depth: 0 persist-credentials: false - name: Set up Java @@ -173,37 +111,50 @@ jobs: java-version: | 8 21 - cache: gradle - name: Set up Gradle - uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - - name: Run tests - run: ./scripts/test - examples: - timeout-minutes: 20 - name: examples - environment: CI - runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.repository == 'openai/openai-java' && github.event_name == 'push' && github.ref == 'refs/heads/main' && github.event.head_commit.message != 'codegen metadata' + - name: Compile previous tests against the proposed SDK + env: + BASE_COMMIT: ${{ github.event.pull_request.base.sha }} + GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process + run: ./scripts/detect-breaking-changes "$BASE_COMMIT" + + required: + name: CI / required + if: always() + needs: + - lint + - build + - test + - api_compatibility + runs-on: ubuntu-24.04 + timeout-minutes: 5 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false + - name: Verify required jobs succeeded + env: + EVENT_NAME: ${{ github.event_name }} + LINT_RESULT: ${{ needs.lint.result }} + BUILD_RESULT: ${{ needs.build.result }} + TEST_RESULT: ${{ needs.test.result }} + API_COMPATIBILITY_RESULT: ${{ needs.api_compatibility.result }} + run: | + set -euo pipefail - - name: Set up Java - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - distribution: temurin - java-version: | - 8 - 21 - cache: gradle - - name: Set up Gradle - uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2 + failed_jobs=() + [[ "$LINT_RESULT" == "success" ]] || failed_jobs+=("lint: $LINT_RESULT") + [[ "$BUILD_RESULT" == "success" ]] || failed_jobs+=("build: $BUILD_RESULT") + [[ "$TEST_RESULT" == "success" ]] || failed_jobs+=("test: $TEST_RESULT") - - env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - run: | - ./gradlew :openai-java-example:run + if [[ "$EVENT_NAME" == "pull_request" && "$API_COMPATIBILITY_RESULT" != "success" ]]; then + failed_jobs+=("API compatibility: $API_COMPATIBILITY_RESULT") + fi + + if (( ${#failed_jobs[@]} > 0 )); then + printf 'Required CI job did not succeed: %s\n' "${failed_jobs[@]}" + exit 1 + fi + + echo "All required CI jobs succeeded." diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 73d193310..4998c1f2a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,4 +1,4 @@ -name: CodeQL +name: Security / CodeQL on: push: @@ -9,14 +9,21 @@ on: - main workflow_dispatch: +permissions: + contents: read + +concurrency: + group: security-codeql-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: analyze: - name: Analyze Java and Kotlin - runs-on: ubuntu-latest + name: Security / CodeQL + runs-on: ubuntu-24.04 timeout-minutes: 45 permissions: contents: read - security-events: write + security-events: write # Upload the SARIF results produced by this analysis. steps: - name: Check out repository @@ -31,7 +38,7 @@ jobs: java-version: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Initialize CodeQL uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4 diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 27852eeac..fc2ec1cd3 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -1,4 +1,5 @@ name: Create releases + on: schedule: - cron: '0 5 * * *' # every day at 5am UTC @@ -9,11 +10,16 @@ on: permissions: contents: read +concurrency: + group: create-releases + cancel-in-progress: false + jobs: release: - name: release + name: Release / create if: github.ref == 'refs/heads/main' && github.repository == 'openai/openai-java' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 + timeout-minutes: 15 environment: publish outputs: releases_created: ${{ steps.release.outputs.releases_created }} @@ -23,75 +29,14 @@ jobs: with: persist-credentials: false - - uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0 + - name: Create release id: release + uses: stainless-api/trigger-release-please@bb6677c5a04578eec1ccfd9e1913b5b78ed64c61 # v1.4.0 with: repo: ${{ github.event.repository.full_name }} stainless-api-key: ${{ secrets.STAINLESS_API_KEY }} publish: - name: publish needs: release - if: ${{ needs.release.outputs.releases_created == 'true' }} - runs-on: ubuntu-latest - environment: publish - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Set up Java - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - distribution: temurin - java-version: | - 8 - 21 - cache: gradle - - - name: Set up Gradle - uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2 - - - name: Compile the openai-java-core project - run: | - ./gradlew :openai-java-core:compileJava :openai-java-core:compileTestJava -x test - - - name: Run the mock server - run: | - ./scripts/mock --daemon - - - name: Setup GraalVM - uses: graalvm/setup-graalvm@03e8abf916fd0e281b2efe7b2da3378bb0a1d085 # v1 - with: - java-version: 21 - distribution: 'graalvm-community' - cache: gradle - - - name: Run tests on the openai-java-core project with the GraalVM native-image agent - run: | - ./gradlew :openai-java-core:test -x compileJava -x compileTestJava -x compileKotlin -x compileTestKotlin -PgraalvmAgent - - - name: Check generated GraalVM file - run: | - echo "Checking for GraalVM agent metadata files..." - DIRECTORY=openai-java-core/src/main/resources/META-INF/native-image - if [ -d "$DIRECTORY" ] && [ "$(ls -A $DIRECTORY)" ]; then - echo "Files found in $DIRECTORY:" - ls -l $DIRECTORY - else - echo "No files found in $DIRECTORY" - exit 1 - fi - - - name: Publish to Sonatype - run: |- - export -- GPG_SIGNING_KEY_ID - printenv -- GPG_SIGNING_KEY | gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD" - GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')" - ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache - env: - SONATYPE_USERNAME: ${{ secrets.OPENAI_SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.OPENAI_SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_PASSWORD }} + if: needs.release.outputs.releases_created == 'true' + uses: ./.github/workflows/publish-sonatype-reusable.yml diff --git a/.github/workflows/detect-breaking-changes.yml b/.github/workflows/detect-breaking-changes.yml deleted file mode 100644 index 94819c587..000000000 --- a/.github/workflows/detect-breaking-changes.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: CI -on: - pull_request: - branches: - - main - - next - -permissions: - contents: read - -jobs: - detect_breaking_changes: - runs-on: 'ubuntu-latest' - name: detect-breaking-changes - if: github.repository == 'openai/openai-java' - steps: - - name: Calculate fetch-depth - run: | - echo "FETCH_DEPTH=$(expr ${{ github.event.pull_request.commits }} + 1)" >> $GITHUB_ENV - - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - # Ensure we can check out the pull request base in the script below. - fetch-depth: ${{ env.FETCH_DEPTH }} - persist-credentials: false - - - name: Set up Java - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - distribution: temurin - java-version: | - 8 - 21 - cache: gradle - - name: Set up Gradle - uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2 - - - name: Detect breaking changes - run: | - # Try to check out previous versions of the breaking change detection script. This ensures that - # we still detect breaking changes when entire files and their tests are removed. - git checkout "${{ github.event.pull_request.base.sha }}" -- ./scripts/detect-breaking-changes 2>/dev/null || true - ./scripts/detect-breaking-changes ${{ github.event.pull_request.base.sha }} diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml new file mode 100644 index 000000000..46fe027a3 --- /dev/null +++ b/.github/workflows/examples.yml @@ -0,0 +1,42 @@ +name: Examples smoke test + +on: + push: + branches: + - main + +permissions: + contents: read + +concurrency: + group: examples-smoke-test-main + cancel-in-progress: true + +jobs: + examples: + name: Examples / live API smoke test + if: github.event.head_commit.message != 'codegen metadata' + environment: ci + runs-on: ubuntu-24.04 + timeout-minutes: 20 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up Java + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: temurin + java-version: | + 8 + 21 + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + + - name: Run example + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + run: ./gradlew :openai-java-example:run diff --git a/.github/workflows/publish-sonatype-reusable.yml b/.github/workflows/publish-sonatype-reusable.yml new file mode 100644 index 000000000..e67a7f5cb --- /dev/null +++ b/.github/workflows/publish-sonatype-reusable.yml @@ -0,0 +1,90 @@ +name: Publish Sonatype (reusable) + +on: + workflow_call: + +permissions: + contents: read + +concurrency: + group: sonatype-publish + cancel-in-progress: false + +jobs: + publish: + name: Publish / Sonatype + runs-on: ubuntu-24.04 + timeout-minutes: 60 + environment: publish + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up Java + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: temurin + java-version: | + 8 + 21 + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + + - name: Compile the openai-java-core project + run: ./gradlew :openai-java-core:compileJava :openai-java-core:compileTestJava -x test + + - name: Run the mock server + run: ./scripts/mock --daemon + + - name: Set up GraalVM + uses: graalvm/setup-graalvm@03e8abf916fd0e281b2efe7b2da3378bb0a1d085 # v1 + with: + java-version: 21 + distribution: graalvm-community + + - name: Run GraalVM native-image agent tests + run: >- + ./gradlew :openai-java-core:test + -x compileJava + -x compileTestJava + -x compileKotlin + -x compileTestKotlin + -PgraalvmAgent + + - name: Check generated GraalVM files + run: | + set -euo pipefail + + directory="openai-java-core/src/main/resources/META-INF/native-image" + if [[ ! -d "$directory" || -z "$(ls -A "$directory")" ]]; then + echo "No files found in $directory" + exit 1 + fi + + echo "Files found in $directory:" + ls -l "$directory" + + - name: Publish to Sonatype + env: + SONATYPE_USERNAME: ${{ secrets.OPENAI_SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.OPENAI_SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_PASSWORD }} + run: |- + set -euo pipefail + + export -- GPG_SIGNING_KEY_ID + printf '%s' "$GPG_SIGNING_KEY" | + gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD" + GPG_SIGNING_KEY_ID="$( + gpg --with-colons --list-keys | + awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }' + )" + ./gradlew publishAndReleaseToMavenCentral \ + --stacktrace \ + -PmavenCentralUsername="$SONATYPE_USERNAME" \ + -PmavenCentralPassword="$SONATYPE_PASSWORD" \ + --no-configuration-cache diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index c99d8eccd..62979e50b 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -1,6 +1,6 @@ -# workflow for re-running publishing to Sonatype in case it fails for some reason -# you can run this workflow by navigating to https://www.github.com/openai/openai-java/actions/workflows/publish-sonatype.yml +# Manual recovery workflow for retrying a failed Sonatype publication. name: Publish Sonatype + on: workflow_dispatch: @@ -9,66 +9,4 @@ permissions: jobs: publish: - name: publish - runs-on: ubuntu-latest - environment: publish - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Set up Java - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - distribution: temurin - java-version: | - 8 - 21 - cache: gradle - - - name: Set up Gradle - uses: gradle/gradle-build-action@fe583dc97e032f41ccc310ea5176f2d7306abbc4 # v2 - - - name: Compile the openai-java-core project - run: | - ./gradlew :openai-java-core:compileJava :openai-java-core:compileTestJava -x test - - - name: Run the mock server - run: | - ./scripts/mock --daemon - - - name: Setup GraalVM - uses: graalvm/setup-graalvm@03e8abf916fd0e281b2efe7b2da3378bb0a1d085 # v1 - with: - java-version: 21 - distribution: 'graalvm-community' - cache: gradle - - - name: Run tests on the openai-java-core project with the GraalVM native-image agent - run: | - ./gradlew :openai-java-core:test -x compileJava -x compileTestJava -x compileKotlin -x compileTestKotlin -PgraalvmAgent - - - name: Check generated GraalVM file - run: | - echo "Checking for GraalVM agent metadata files..." - DIRECTORY=openai-java-core/src/main/resources/META-INF/native-image - if [ -d "$DIRECTORY" ] && [ "$(ls -A $DIRECTORY)" ]; then - echo "Files found in $DIRECTORY:" - ls -l $DIRECTORY - else - echo "No files found in $DIRECTORY" - exit 1 - fi - - - name: Publish to Sonatype - run: |- - export -- GPG_SIGNING_KEY_ID - printenv -- GPG_SIGNING_KEY | gpg --batch --passphrase-fd 3 --import 3<<< "$GPG_SIGNING_PASSWORD" - GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')" - ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache - env: - SONATYPE_USERNAME: ${{ secrets.OPENAI_SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.OPENAI_SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.OPENAI_SONATYPE_GPG_SIGNING_PASSWORD }} + uses: ./.github/workflows/publish-sonatype-reusable.yml diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 30b23334a..998e3f453 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -6,17 +6,23 @@ cd "$(dirname "$0")/.." echo "==> Detecting breaking changes" +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " >&2 + exit 2 +fi + +BASE_COMMIT="$1" + +git cat-file -e "${BASE_COMMIT}^{commit}" + TEST_PATHS=( openai-java-core/src/test/kotlin/com/openai/models openai-java-core/src/test/kotlin/com/openai/services ) for PATHSPEC in "${TEST_PATHS[@]}"; do - # Try to check out previous versions of the test files - # with the current SDK. - git checkout "$1" -- "${PATHSPEC}" 2>/dev/null || true + # Compile the previous tests against the proposed SDK so removed or incompatible APIs fail. + git checkout "${BASE_COMMIT}" -- "${PATHSPEC}" done -# Instead of running the tests, use the linter to check if an -# older test is no longer compatible with the latest SDK. -./scripts/lint +./scripts/gradle :openai-java-core:testClasses --no-build-cache From d9fadb7e9b0c554179f80ecb626dc1830055ebbd Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 16:31:59 -0700 Subject: [PATCH 02/23] Address CI review feedback --- scripts/detect-breaking-changes | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 998e3f453..8ca05e2be 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -20,9 +20,21 @@ TEST_PATHS=( openai-java-core/src/test/kotlin/com/openai/services ) +RESTORED_PATHS=0 for PATHSPEC in "${TEST_PATHS[@]}"; do + if ! git cat-file -e "${BASE_COMMIT}:${PATHSPEC}" 2>/dev/null; then + echo "Skipping test path absent from base commit: ${PATHSPEC}" + continue + fi + # Compile the previous tests against the proposed SDK so removed or incompatible APIs fail. git checkout "${BASE_COMMIT}" -- "${PATHSPEC}" + RESTORED_PATHS=$((RESTORED_PATHS + 1)) done +if [ "${RESTORED_PATHS}" -eq 0 ]; then + echo "No baseline test paths were found in ${BASE_COMMIT}" >&2 + exit 1 +fi + ./scripts/gradle :openai-java-core:testClasses --no-build-cache From c75b1051be53c56b510643d3024b3ff02fc728ce Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 16:59:33 -0700 Subject: [PATCH 03/23] Make Mockito agent configuration lazy --- openai-java-core/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/openai-java-core/build.gradle.kts b/openai-java-core/build.gradle.kts index e38ef8439..f36399698 100644 --- a/openai-java-core/build.gradle.kts +++ b/openai-java-core/build.gradle.kts @@ -22,6 +22,7 @@ val mockitoVersion = "5.14.2" val mockitoAgent by configurations.creating { isCanBeConsumed = false isCanBeResolved = true + isVisible = false } // Runtime classpath for `testJacksonCompatibility`: the same dependencies as From 83fe31c731d7d1156fdc684ce3fc4f10b1d432f3 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 17:26:53 -0700 Subject: [PATCH 04/23] Remove unused Bedrock Mockito dependencies --- openai-java-bedrock/build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/openai-java-bedrock/build.gradle.kts b/openai-java-bedrock/build.gradle.kts index 6d433376c..97d43c779 100644 --- a/openai-java-bedrock/build.gradle.kts +++ b/openai-java-bedrock/build.gradle.kts @@ -39,6 +39,4 @@ dependencies { testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.junit-pioneer:junit-pioneer:1.9.1") - testImplementation("org.mockito:mockito-core:5.14.2") - testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") } From cd6b58d1f9e86097d0076e00d74ac8d854758229 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 19:35:39 -0700 Subject: [PATCH 05/23] Address automated CI review feedback --- .github/workflows/ci.yml | 16 +++- .github/workflows/examples.yml | 4 +- .../workflows/stainless-maven-artifacts.yml | 94 +++++++++++++++++++ openai-java-core/build.gradle.kts | 19 ++++ scripts/detect-breaking-changes | 69 ++++++++++++-- 5 files changed, 193 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/stainless-maven-artifacts.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f03681b43..2569580fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,10 @@ jobs: build: name: CI / build + Jackson compatibility + if: >- + !(github.repository == 'stainless-sdks/openai-java' && + github.event_name == 'push' && + !startsWith(github.ref, 'refs/heads/stl/')) runs-on: ubuntu-24.04 timeout-minutes: 30 @@ -136,6 +140,8 @@ jobs: - name: Verify required jobs succeeded env: EVENT_NAME: ${{ github.event_name }} + REPOSITORY: ${{ github.repository }} + REF: ${{ github.ref }} LINT_RESULT: ${{ needs.lint.result }} BUILD_RESULT: ${{ needs.build.result }} TEST_RESULT: ${{ needs.test.result }} @@ -145,9 +151,17 @@ jobs: failed_jobs=() [[ "$LINT_RESULT" == "success" ]] || failed_jobs+=("lint: $LINT_RESULT") - [[ "$BUILD_RESULT" == "success" ]] || failed_jobs+=("build: $BUILD_RESULT") [[ "$TEST_RESULT" == "success" ]] || failed_jobs+=("test: $TEST_RESULT") + if [[ "$EVENT_NAME" == "push" && + "$REPOSITORY" == "stainless-sdks/openai-java" && + "$REF" != refs/heads/stl/* ]]; then + [[ "$BUILD_RESULT" == "skipped" ]] || + failed_jobs+=("build: expected skipped, got $BUILD_RESULT") + else + [[ "$BUILD_RESULT" == "success" ]] || failed_jobs+=("build: $BUILD_RESULT") + fi + if [[ "$EVENT_NAME" == "pull_request" && "$API_COMPATIBILITY_RESULT" != "success" ]]; then failed_jobs+=("API compatibility: $API_COMPATIBILITY_RESULT") fi diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 46fe027a3..4248eb48c 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -15,7 +15,9 @@ concurrency: jobs: examples: name: Examples / live API smoke test - if: github.event.head_commit.message != 'codegen metadata' + if: >- + github.repository == 'openai/openai-java' && + github.event.head_commit.message != 'codegen metadata' environment: ci runs-on: ubuntu-24.04 timeout-minutes: 20 diff --git a/.github/workflows/stainless-maven-artifacts.yml b/.github/workflows/stainless-maven-artifacts.yml new file mode 100644 index 000000000..d8561fadd --- /dev/null +++ b/.github/workflows/stainless-maven-artifacts.yml @@ -0,0 +1,94 @@ +name: Stainless Maven artifacts + +on: + push: + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' + +permissions: + contents: read + +jobs: + upload: + name: Stainless / publish Maven artifacts + if: >- + github.repository == 'stainless-sdks/openai-java' && + github.event.head_commit.message != 'codegen metadata' && + !startsWith(github.ref, 'refs/heads/stl/') + permissions: + contents: read + id-token: write + runs-on: depot-ubuntu-24.04 + timeout-minutes: 30 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up Java + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: temurin + java-version: | + 8 + 21 + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + + - name: Build SDK + env: + GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process + run: ./scripts/build + + - name: Upload Maven artifacts + env: + URL: https://pkg.stainless.com/s + SHA: ${{ github.sha }} + PROJECT: openai-java + run: | + set -euo pipefail + + max_retries=5 + attempt=1 + + while true; do + echo "Maven artifact upload attempt ${attempt}/${max_retries}" + + oidc_response="$( + curl -sSf \ + -H "Authorization: bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \ + "${ACTIONS_ID_TOKEN_REQUEST_URL}" + )" + github_token="$(printf '%s' "$oidc_response" | jq -er '.value')" + + upload_log="$(mktemp)" + set +e + AUTH="$github_token" ./scripts/upload-artifacts 2>&1 | tee "$upload_log" + upload_status=${PIPESTATUS[0]} + set -e + + if [ "$upload_status" -eq 0 ]; then + break + fi + + if [[ "$attempt" -lt "$max_retries" ]] && + grep -q "Failed to get valid signed URL" "$upload_log" && + grep -q "GitHub JWT is missing or invalid\\." "$upload_log"; then + sleep_seconds=$((3 * (1 << (attempt - 1)))) + echo "Retrying after fresh OIDC token due to transient GitHub JWT validation failure" + echo "Sleeping ${sleep_seconds}s before retry" + sleep "$sleep_seconds" + attempt=$((attempt + 1)) + continue + fi + + exit "$upload_status" + done diff --git a/openai-java-core/build.gradle.kts b/openai-java-core/build.gradle.kts index f36399698..82ce09476 100644 --- a/openai-java-core/build.gradle.kts +++ b/openai-java-core/build.gradle.kts @@ -25,6 +25,25 @@ val mockitoAgent by configurations.creating { isVisible = false } +// Compiles tests restored from the base commit as external consumers of the proposed SDK. Unlike +// the normal test source set, this source set is not a Kotlin friend of main, so `internal` +// implementation details are excluded from the compatibility surface. +val apiCompatibility by sourceSets.creating { + kotlin.srcDir( + layout.buildDirectory.dir( + "api-compatibility-source/openai-java-core/src/test/kotlin" + ) + ) + compileClasspath += sourceSets.main.get().output +} +configurations[apiCompatibility.implementationConfigurationName].extendsFrom( + configurations.testImplementation.get() +) +configurations[apiCompatibility.compileClasspathConfigurationName].attributes.attribute( + org.gradle.api.attributes.java.TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, + 17, +) + // Runtime classpath for `testJacksonCompatibility`: the same dependencies as // `testRuntimeClasspath`, but forced to the older Jackson version that the SDK supports. val jacksonCompatibilityRuntime by configurations.creating { diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 8ca05e2be..1530db164 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -e +set -euo pipefail cd "$(dirname "$0")/.." @@ -20,21 +20,76 @@ TEST_PATHS=( openai-java-core/src/test/kotlin/com/openai/services ) -RESTORED_PATHS=0 +SUPPORT_PATHS=( + openai-java-core/src/test/kotlin/com/openai/TestServerExtension.kt + openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt +) + +# These generated tests explicitly exercise Kotlin `internal` helpers. They remain covered by the +# normal test suite, but are not consumer fixtures and must not define the public compatibility +# surface. +INTERNAL_FIXTURES=( + openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt + openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt + openai-java-core/src/test/kotlin/com/openai/models/containers/files/FileCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/files/FileCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/images/ImageEditParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt + openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt + openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt + openai-java-core/src/test/kotlin/com/openai/models/skills/SkillCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/skills/versions/VersionCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/uploads/parts/PartCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/videos/VideoCreateCharacterParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/videos/VideoCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/videos/VideoEditParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/videos/VideoExtendParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/videos/VideoRemixParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt +) + +COMPATIBILITY_ROOT="openai-java-core/build/api-compatibility-source" +rm -rf "${COMPATIBILITY_ROOT}" +mkdir -p "${COMPATIBILITY_ROOT}" + +RESTORED_TEST_PATHS=0 for PATHSPEC in "${TEST_PATHS[@]}"; do if ! git cat-file -e "${BASE_COMMIT}:${PATHSPEC}" 2>/dev/null; then echo "Skipping test path absent from base commit: ${PATHSPEC}" continue fi - # Compile the previous tests against the proposed SDK so removed or incompatible APIs fail. - git checkout "${BASE_COMMIT}" -- "${PATHSPEC}" - RESTORED_PATHS=$((RESTORED_PATHS + 1)) + # Extract the previous tests into an isolated source tree. This avoids collisions with renamed + # current tests and keeps the working tree untouched. + git archive "${BASE_COMMIT}" -- "${PATHSPEC}" | tar -x -C "${COMPATIBILITY_ROOT}" + RESTORED_TEST_PATHS=$((RESTORED_TEST_PATHS + 1)) done -if [ "${RESTORED_PATHS}" -eq 0 ]; then +if [ "${RESTORED_TEST_PATHS}" -eq 0 ]; then echo "No baseline test paths were found in ${BASE_COMMIT}" >&2 exit 1 fi -./scripts/gradle :openai-java-core:testClasses --no-build-cache +for PATHSPEC in "${SUPPORT_PATHS[@]}"; do + if ! git cat-file -e "${BASE_COMMIT}:${PATHSPEC}" 2>/dev/null; then + echo "Skipping support path absent from base commit: ${PATHSPEC}" + continue + fi + + git archive "${BASE_COMMIT}" -- "${PATHSPEC}" | tar -x -C "${COMPATIBILITY_ROOT}" +done + +for PATHSPEC in "${INTERNAL_FIXTURES[@]}"; do + GENERATED_PATH="${COMPATIBILITY_ROOT}/${PATHSPEC}" + if [ -f "${GENERATED_PATH}" ]; then + echo "Excluding internal-only compatibility fixture: ${PATHSPEC}" + rm "${GENERATED_PATH}" + fi +done + +./scripts/gradle :openai-java-core:compileApiCompatibilityKotlin --no-build-cache From b03c3ceec87b8048d40ea1cf13fc1bca944e61aa Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 19:56:16 -0700 Subject: [PATCH 06/23] Avoid duplicate CodeQL analysis --- .github/workflows/codeql.yml | 55 ------------------------------------ 1 file changed, 55 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 4998c1f2a..000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Security / CodeQL - -on: - push: - branches: - - main - pull_request: - branches: - - main - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: security-codeql-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} - -jobs: - analyze: - name: Security / CodeQL - runs-on: ubuntu-24.04 - timeout-minutes: 45 - permissions: - contents: read - security-events: write # Upload the SARIF results produced by this analysis. - - steps: - - name: Check out repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Set up Java - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 - with: - distribution: temurin - java-version: 21 - - - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4 - with: - languages: java-kotlin - build-mode: manual - - - name: Build SDK - env: - GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process - run: ./scripts/build --no-build-cache - - - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4 From dc202fe411410422a3b723dd98439930984173ad Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 20:06:49 -0700 Subject: [PATCH 07/23] Close API compatibility coverage gaps --- .github/workflows/ci.yml | 13 ++++++++++++- .github/workflows/examples.yml | 2 +- scripts/detect-breaking-changes | 27 +++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2569580fe..d14a0bf66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,7 +123,18 @@ jobs: env: BASE_COMMIT: ${{ github.event.pull_request.base.sha }} GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process - run: ./scripts/detect-breaking-changes "$BASE_COMMIT" + run: | + set -euo pipefail + + # The proposed detector verifies the current compatibility policy. Running the baseline + # detector as well prevents a PR from weakening that policy to hide an SDK break. + ./scripts/detect-breaking-changes "$BASE_COMMIT" + + BASE_DETECTOR="$(mktemp ./scripts/detect-breaking-changes.baseline.XXXXXX)" + trap 'rm -f "$BASE_DETECTOR"' EXIT + git show "${BASE_COMMIT}:scripts/detect-breaking-changes" > "$BASE_DETECTOR" + chmod +x "$BASE_DETECTOR" + "$BASE_DETECTOR" "$BASE_COMMIT" required: name: CI / required diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 4248eb48c..72648d6d0 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -18,7 +18,7 @@ jobs: if: >- github.repository == 'openai/openai-java' && github.event.head_commit.message != 'codegen metadata' - environment: ci + environment: CI runs-on: ubuntu-24.04 timeout-minutes: 20 diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 1530db164..6bfb96151 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -39,8 +39,6 @@ INTERNAL_FIXTURES=( openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/images/ImageEditParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt - openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt openai-java-core/src/test/kotlin/com/openai/models/skills/SkillCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/skills/versions/VersionCreateParamsTest.kt @@ -92,4 +90,29 @@ for PATHSPEC in "${INTERNAL_FIXTURES[@]}"; do fi done +# Keep the public API coverage in these structured-output fixtures while replacing their one +# assertion that calls the Kotlin-internal JsonField.getRequired helper. +sanitize_internal_assertion() { + local file_path="$1" + local internal_assertion="$2" + local public_assertion="$3" + + if ! grep -Fq "${internal_assertion}" "${file_path}"; then + echo "Expected internal assertion was not found in ${file_path}" >&2 + exit 1 + fi + + INTERNAL_ASSERTION="${internal_assertion}" PUBLIC_ASSERTION="${public_assertion}" \ + perl -0pi -e 's/\Q$ENV{INTERNAL_ASSERTION}\E/$ENV{PUBLIC_ASSERTION}/g' "${file_path}" +} + +sanitize_internal_assertion \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt" \ + 'assertThat(output.getRequired("content")[0].rawContent).isEqualTo(CONTENT)' \ + 'assertThat(output).isEqualTo(input)' +sanitize_internal_assertion \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt" \ + 'assertThat(output.getRequired("_output")[0].rawOutputItem).isEqualTo(OUTPUT_ITEM)' \ + 'assertThat(output).isEqualTo(input)' + ./scripts/gradle :openai-java-core:compileApiCompatibilityKotlin --no-build-cache From ebb5f1856063e25c3f3756b314b67ad4e7e23636 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 20:27:12 -0700 Subject: [PATCH 08/23] Preserve structured chat compatibility coverage --- scripts/detect-breaking-changes | 45 +++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 6bfb96151..bcb2c9da3 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -32,8 +32,6 @@ INTERNAL_FIXTURES=( openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt - openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt openai-java-core/src/test/kotlin/com/openai/models/containers/files/FileCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/files/FileCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt @@ -90,27 +88,48 @@ for PATHSPEC in "${INTERNAL_FIXTURES[@]}"; do fi done -# Keep the public API coverage in these structured-output fixtures while replacing their one -# assertion that calls the Kotlin-internal JsonField.getRequired helper. -sanitize_internal_assertion() { +# Keep the public API coverage in structured-output fixtures while replacing only references to +# Kotlin-internal constructors and JsonField helpers. +replace_internal_reference() { local file_path="$1" - local internal_assertion="$2" - local public_assertion="$3" + local internal_source="$2" + local public_source="$3" - if ! grep -Fq "${internal_assertion}" "${file_path}"; then - echo "Expected internal assertion was not found in ${file_path}" >&2 + if [ ! -f "${file_path}" ]; then + echo "Expected compatibility fixture was not restored: ${file_path}" >&2 exit 1 fi - INTERNAL_ASSERTION="${internal_assertion}" PUBLIC_ASSERTION="${public_assertion}" \ - perl -0pi -e 's/\Q$ENV{INTERNAL_ASSERTION}\E/$ENV{PUBLIC_ASSERTION}/g' "${file_path}" + if ! grep -Fq "${internal_source}" "${file_path}"; then + echo "Expected internal reference was not found in ${file_path}" >&2 + exit 1 + fi + + INTERNAL_SOURCE="${internal_source}" PUBLIC_SOURCE="${public_source}" \ + perl -0pi -e 's/\Q$ENV{INTERNAL_SOURCE}\E/$ENV{PUBLIC_SOURCE}/g' "${file_path}" } -sanitize_internal_assertion \ +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt" \ + 'StructuredChatCompletionMessage(X::class.java, mockDelegate)' \ + 'mock(StructuredChatCompletionMessage::class.java) as StructuredChatCompletionMessage' +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt" \ + 'StructuredChatCompletion.Choice(X::class.java, mockChoiceDelegate)' \ + 'mock(StructuredChatCompletion.Choice::class.java) as StructuredChatCompletion.Choice' +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt" \ + 'assertThat(output.getRequired("_choices")[0].rawChoice).isEqualTo(CHOICE)' \ + 'assertThat(output).isEqualTo(input)' +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt" \ + 'assertThat(output.getRequired("_message").rawMessage).isEqualTo(MESSAGE)' \ + 'assertThat(output).isEqualTo(input)' +replace_internal_reference \ "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt" \ 'assertThat(output.getRequired("content")[0].rawContent).isEqualTo(CONTENT)' \ 'assertThat(output).isEqualTo(input)' -sanitize_internal_assertion \ +replace_internal_reference \ "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt" \ 'assertThat(output.getRequired("_output")[0].rawOutputItem).isEqualTo(OUTPUT_ITEM)' \ 'assertThat(output).isEqualTo(input)' From 23c787ab7831991e5fa5087dd6c732961409d176 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 20:46:49 -0700 Subject: [PATCH 09/23] Make API compatibility policy self-contained --- openai-java-core/build.gradle.kts | 19 ------------- scripts/detect-breaking-changes | 44 +++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/openai-java-core/build.gradle.kts b/openai-java-core/build.gradle.kts index 82ce09476..f36399698 100644 --- a/openai-java-core/build.gradle.kts +++ b/openai-java-core/build.gradle.kts @@ -25,25 +25,6 @@ val mockitoAgent by configurations.creating { isVisible = false } -// Compiles tests restored from the base commit as external consumers of the proposed SDK. Unlike -// the normal test source set, this source set is not a Kotlin friend of main, so `internal` -// implementation details are excluded from the compatibility surface. -val apiCompatibility by sourceSets.creating { - kotlin.srcDir( - layout.buildDirectory.dir( - "api-compatibility-source/openai-java-core/src/test/kotlin" - ) - ) - compileClasspath += sourceSets.main.get().output -} -configurations[apiCompatibility.implementationConfigurationName].extendsFrom( - configurations.testImplementation.get() -) -configurations[apiCompatibility.compileClasspathConfigurationName].attributes.attribute( - org.gradle.api.attributes.java.TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, - 17, -) - // Runtime classpath for `testJacksonCompatibility`: the same dependencies as // `testRuntimeClasspath`, but forced to the older Jackson version that the SDK supports. val jacksonCompatibilityRuntime by configurations.creating { diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index bcb2c9da3..d840426a2 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -96,13 +96,13 @@ replace_internal_reference() { local public_source="$3" if [ ! -f "${file_path}" ]; then - echo "Expected compatibility fixture was not restored: ${file_path}" >&2 - exit 1 + echo "Skipping compatibility rewrite; fixture was not restored: ${file_path}" >&2 + return fi if ! grep -Fq "${internal_source}" "${file_path}"; then - echo "Expected internal reference was not found in ${file_path}" >&2 - exit 1 + echo "Skipping compatibility rewrite; internal reference is absent: ${file_path}" >&2 + return fi INTERNAL_SOURCE="${internal_source}" PUBLIC_SOURCE="${public_source}" \ @@ -134,4 +134,38 @@ replace_internal_reference \ 'assertThat(output.getRequired("_output")[0].rawOutputItem).isEqualTo(OUTPUT_ITEM)' \ 'assertThat(output).isEqualTo(input)' -./scripts/gradle :openai-java-core:compileApiCompatibilityKotlin --no-build-cache +# Keep the compatibility compilation policy in this detector rather than in the proposed build +# file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy +# by weakening a source set or task in openai-java-core/build.gradle.kts. +COMPATIBILITY_SOURCE_ROOT="$(pwd)/${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" +COMPATIBILITY_INIT_SCRIPT="$(mktemp "${TMPDIR:-/tmp}/openai-java-api-compatibility.XXXXXX.gradle")" +trap 'rm -f "${COMPATIBILITY_INIT_SCRIPT}"' EXIT + +cat > "${COMPATIBILITY_INIT_SCRIPT}" <<'GRADLE' +import org.gradle.api.attributes.java.TargetJvmVersion + +gradle.beforeProject { project -> + if (project.path == ":openai-java-core") { + project.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { + def sourceSets = project.extensions.getByName("sourceSets") + def compatibility = sourceSets.create("externalApiCompatibility") + compatibility.kotlin.srcDir(System.getenv("COMPATIBILITY_SOURCE_ROOT")) + compatibility.compileClasspath += sourceSets.getByName("main").output + + project.configurations + .getByName(compatibility.implementationConfigurationName) + .extendsFrom(project.configurations.getByName("testImplementation")) + project.configurations + .getByName(compatibility.compileClasspathConfigurationName) + .attributes + .attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) + } + } +} +GRADLE + +COMPATIBILITY_SOURCE_ROOT="${COMPATIBILITY_SOURCE_ROOT}" \ + ./scripts/gradle \ + --init-script "${COMPATIBILITY_INIT_SCRIPT}" \ + :openai-java-core:compileExternalApiCompatibilityKotlin \ + --no-build-cache From 8e3c187194880ac41d875610299249df03f2e11f Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 20:54:54 -0700 Subject: [PATCH 10/23] Clean up Stainless upload logs --- .github/workflows/stainless-maven-artifacts.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/stainless-maven-artifacts.yml b/.github/workflows/stainless-maven-artifacts.yml index d8561fadd..a4b10da05 100644 --- a/.github/workflows/stainless-maven-artifacts.yml +++ b/.github/workflows/stainless-maven-artifacts.yml @@ -58,6 +58,15 @@ jobs: max_retries=5 attempt=1 + upload_log="" + + cleanup_upload_log() { + if [ -n "$upload_log" ]; then + rm -f "$upload_log" + upload_log="" + fi + } + trap cleanup_upload_log EXIT while true; do echo "Maven artifact upload attempt ${attempt}/${max_retries}" @@ -76,12 +85,14 @@ jobs: set -e if [ "$upload_status" -eq 0 ]; then + cleanup_upload_log break fi if [[ "$attempt" -lt "$max_retries" ]] && grep -q "Failed to get valid signed URL" "$upload_log" && grep -q "GitHub JWT is missing or invalid\\." "$upload_log"; then + cleanup_upload_log sleep_seconds=$((3 * (1 << (attempt - 1)))) echo "Retrying after fresh OIDC token due to transient GitHub JWT validation failure" echo "Sleeping ${sleep_seconds}s before retry" From 48d02c92b898dc67df3e8dd354444ba21b12bbe9 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 21:13:06 -0700 Subject: [PATCH 11/23] Preserve structured text compatibility coverage --- .../workflows/stainless-maven-artifacts.yml | 3 +++ scripts/detect-breaking-changes | 23 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stainless-maven-artifacts.yml b/.github/workflows/stainless-maven-artifacts.yml index a4b10da05..9b6e94188 100644 --- a/.github/workflows/stainless-maven-artifacts.yml +++ b/.github/workflows/stainless-maven-artifacts.yml @@ -1,5 +1,8 @@ name: Stainless Maven artifacts +# GitHub Actions does not support repository filters on workflow triggers. Keep this push trigger in +# shared history so the Stainless fork inherits artifact publication; upstream runs stop at the +# uniquely named, non-required skipped job below. on: push: branches: diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index d840426a2..1d9aaca2b 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -37,7 +37,6 @@ INTERNAL_FIXTURES=( openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/images/ImageEditParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt openai-java-core/src/test/kotlin/com/openai/models/skills/SkillCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/skills/versions/VersionCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/uploads/parts/PartCreateParamsTest.kt @@ -133,6 +132,28 @@ replace_internal_reference \ "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt" \ 'assertThat(output.getRequired("_output")[0].rawOutputItem).isEqualTo(OUTPUT_ITEM)' \ 'assertThat(output).isEqualTo(input)' +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt" \ + 'import com.openai.core.jsonSchemaFromClass +' \ + '' +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt" \ + 'StructuredResponseTextConfig.builder().inject(mockBuilderDelegate)' \ + 'StructuredResponseTextConfig.builder() + .format(X::class.java) + .verbosity(VERBOSITY) + .verbosity(java.util.Optional.of(VERBOSITY)) + .verbosity(com.openai.core.JsonField.of(VERBOSITY)) + .additionalProperties(emptyMap()) + .putAdditionalProperty("key", com.openai.core.JsonValue.from("value")) + .putAllAdditionalProperties(emptyMap()) + .removeAdditionalProperty("key") + .removeAllAdditionalProperties(emptySet())' +replace_internal_reference \ + "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt" \ + 'jsonSchemaFromClass(X::class.java)' \ + 'mock(ResponseFormatTextJsonSchemaConfig::class.java)' # Keep the compatibility compilation policy in this detector rather than in the proposed build # file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy From 8b42f3f4d6dcda374ee7a20f373edc23a0370a69 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 21:19:58 -0700 Subject: [PATCH 12/23] Upgrade Gradle setup action to Node 24 --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/examples.yml | 2 +- .github/workflows/publish-sonatype-reusable.yml | 2 +- .github/workflows/stainless-maven-artifacts.yml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d14a0bf66..91fc2590e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Run lints run: ./scripts/lint @@ -65,7 +65,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Build SDK and run compatibility tests env: @@ -91,7 +91,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Run tests run: ./scripts/test @@ -117,7 +117,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Compile previous tests against the proposed SDK env: diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 72648d6d0..dbf483206 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -36,7 +36,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Run example env: diff --git a/.github/workflows/publish-sonatype-reusable.yml b/.github/workflows/publish-sonatype-reusable.yml index e67a7f5cb..96b4137ab 100644 --- a/.github/workflows/publish-sonatype-reusable.yml +++ b/.github/workflows/publish-sonatype-reusable.yml @@ -31,7 +31,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Compile the openai-java-core project run: ./gradlew :openai-java-core:compileJava :openai-java-core:compileTestJava -x test diff --git a/.github/workflows/stainless-maven-artifacts.yml b/.github/workflows/stainless-maven-artifacts.yml index 9b6e94188..627f3ea37 100644 --- a/.github/workflows/stainless-maven-artifacts.yml +++ b/.github/workflows/stainless-maven-artifacts.yml @@ -44,7 +44,7 @@ jobs: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Build SDK env: From 43790feade64e0c6112864edb3736be927dad241 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 23 Jul 2026 21:23:53 -0700 Subject: [PATCH 13/23] Use portable compatibility temp file --- scripts/detect-breaking-changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 1d9aaca2b..76b76741b 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -159,7 +159,7 @@ replace_internal_reference \ # file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy # by weakening a source set or task in openai-java-core/build.gradle.kts. COMPATIBILITY_SOURCE_ROOT="$(pwd)/${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" -COMPATIBILITY_INIT_SCRIPT="$(mktemp "${TMPDIR:-/tmp}/openai-java-api-compatibility.XXXXXX.gradle")" +COMPATIBILITY_INIT_SCRIPT="$(mktemp)" trap 'rm -f "${COMPATIBILITY_INIT_SCRIPT}"' EXIT cat > "${COMPATIBILITY_INIT_SCRIPT}" <<'GRADLE' From f18474a840ae3c090a3a62605ed1e3f7eaf2db29 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 09:16:30 -0700 Subject: [PATCH 14/23] fix(ci): retain security CodeQL analysis --- .github/workflows/codeql.yml | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..73d193310 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,48 @@ +name: CodeQL + +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + analyze: + name: Analyze Java and Kotlin + runs-on: ubuntu-latest + timeout-minutes: 45 + permissions: + contents: read + security-events: write + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up Java + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: temurin + java-version: 21 + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4 + with: + languages: java-kotlin + build-mode: manual + + - name: Build SDK + env: + GRADLE_OPTS: -Dkotlin.compiler.execution.strategy=in-process + run: ./scripts/build --no-build-cache + + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4 From 3a09e35fdb206e8a312bcc8e59d63c348e9ebc0e Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 09:46:28 -0700 Subject: [PATCH 15/23] Preserve multipart compatibility coverage --- scripts/detect-breaking-changes | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 76b76741b..c7da5c127 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -25,18 +25,25 @@ SUPPORT_PATHS=( openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt ) -# These generated tests explicitly exercise Kotlin `internal` helpers. They remain covered by the -# normal test suite, but are not consumer fixtures and must not define the public compatibility -# surface. +# These generated tests explicitly exercise Kotlin `internal` structured-output or validation +# helpers. They remain covered by the normal test suite, but are not consumer fixtures and must not +# define the public compatibility surface. INTERNAL_FIXTURES=( + openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt + openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt +) + +# Multipart fixtures exercise public parameter builders and union factories, but their generated +# recursive-comparison assertions call the Kotlin-internal `MultipartField.map` helper. Preserve +# each fixture and rewrite only that internal assertion expression. +MULTIPART_FIXTURES=( openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/containers/files/FileCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/files/FileCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/images/ImageEditParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/skills/SkillCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/skills/versions/VersionCreateParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/uploads/parts/PartCreateParamsTest.kt @@ -45,7 +52,6 @@ INTERNAL_FIXTURES=( openai-java-core/src/test/kotlin/com/openai/models/videos/VideoEditParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/videos/VideoExtendParamsTest.kt openai-java-core/src/test/kotlin/com/openai/models/videos/VideoRemixParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt ) COMPATIBILITY_ROOT="openai-java-core/build/api-compatibility-source" @@ -108,6 +114,13 @@ replace_internal_reference() { perl -0pi -e 's/\Q$ENV{INTERNAL_SOURCE}\E/$ENV{PUBLIC_SOURCE}/g' "${file_path}" } +for PATHSPEC in "${MULTIPART_FIXTURES[@]}"; do + replace_internal_reference \ + "${COMPATIBILITY_ROOT}/${PATHSPEC}" \ + 'field.map { (it as? ByteArray)?.inputStream() ?: it }' \ + 'field' +done + replace_internal_reference \ "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt" \ 'StructuredChatCompletionMessage(X::class.java, mockDelegate)' \ From 8d588618e7c2a5a57d4cdc7b14475dac30319c64 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 10:01:55 -0700 Subject: [PATCH 16/23] fix(ci): preserve remaining compatibility coverage --- .github/workflows/ci.yml | 1 + scripts/detect-breaking-changes | 55 ++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91fc2590e..ef063d0b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: branches: - main - next + - 'stl/**' pull_request: branches: - main diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index c7da5c127..177fc04e6 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -25,13 +25,11 @@ SUPPORT_PATHS=( openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt ) -# These generated tests explicitly exercise Kotlin `internal` structured-output or validation -# helpers. They remain covered by the normal test suite, but are not consumer fixtures and must not -# define the public compatibility surface. +# This generated test explicitly exercises Kotlin `internal` structured-output helpers. It remains +# covered by the normal test suite, but is not a consumer fixture and must not define the public +# compatibility surface. INTERNAL_FIXTURES=( openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt ) # Multipart fixtures exercise public parameter builders and union factories, but their generated @@ -93,6 +91,53 @@ for PATHSPEC in "${INTERNAL_FIXTURES[@]}"; do fi done +# These baseline tests combine public API coverage with Kotlin-internal implementation setup. +# Replace them with consumer-style fixtures that preserve the public expressions without relying on +# internal constructors or helpers. +cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt" <<'KOTLIN' +package com.openai.models.responses + +import com.openai.models.ChatModel +import com.openai.services.async.ResponseServiceAsync +import com.openai.services.blocking.ResponseService + +internal class StructuredResponseOutput(val value: String) + +internal fun publicBuilder(): StructuredResponseCreateParams = + StructuredResponseCreateParams.builder() + .input("input") + .model(ChatModel.GPT_4O_MINI) + .text(StructuredResponseOutput::class.java) + .build() + +internal fun blockingServiceOverloads( + service: ResponseService, + params: StructuredResponseCreateParams, +) { + service.create(params) + service.createStreaming(params) +} + +internal fun asyncServiceOverloads( + service: ResponseServiceAsync, + params: StructuredResponseCreateParams, +) { + service.create(params) + service.createStreaming(params) +} +KOTLIN + +cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt" <<'KOTLIN' +package com.openai.services + +import com.openai.models.responses.ResponseStreamEvent + +internal class ResponseStreamEventValidationTest { + fun outputTextDelta(event: ResponseStreamEvent): String? = + if (event.isOutputTextDelta()) event.asOutputTextDelta().delta() else null +} +KOTLIN + # Keep the public API coverage in structured-output fixtures while replacing only references to # Kotlin-internal constructors and JsonField helpers. replace_internal_reference() { From b0db013918944965aaaeba80feaf765d80041a8b Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 10:26:49 -0700 Subject: [PATCH 17/23] fix(ci): retain structured chat compatibility --- scripts/detect-breaking-changes | 48 ++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 177fc04e6..23d7272ad 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -25,13 +25,6 @@ SUPPORT_PATHS=( openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt ) -# This generated test explicitly exercises Kotlin `internal` structured-output helpers. It remains -# covered by the normal test suite, but is not a consumer fixture and must not define the public -# compatibility surface. -INTERNAL_FIXTURES=( - openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt -) - # Multipart fixtures exercise public parameter builders and union factories, but their generated # recursive-comparison assertions call the Kotlin-internal `MultipartField.map` helper. Preserve # each fixture and rewrite only that internal assertion expression. @@ -83,17 +76,42 @@ for PATHSPEC in "${SUPPORT_PATHS[@]}"; do git archive "${BASE_COMMIT}" -- "${PATHSPEC}" | tar -x -C "${COMPATIBILITY_ROOT}" done -for PATHSPEC in "${INTERNAL_FIXTURES[@]}"; do - GENERATED_PATH="${COMPATIBILITY_ROOT}/${PATHSPEC}" - if [ -f "${GENERATED_PATH}" ]; then - echo "Excluding internal-only compatibility fixture: ${PATHSPEC}" - rm "${GENERATED_PATH}" - fi -done - # These baseline tests combine public API coverage with Kotlin-internal implementation setup. # Replace them with consumer-style fixtures that preserve the public expressions without relying on # internal constructors or helpers. +cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt" <<'KOTLIN' +package com.openai.models.chat.completions + +import com.openai.models.ChatModel +import com.openai.services.async.chat.ChatCompletionServiceAsync +import com.openai.services.blocking.chat.ChatCompletionService + +internal class StructuredChatOutput(val value: String) + +internal fun publicBuilder(): StructuredChatCompletionCreateParams = + StructuredChatCompletionCreateParams.builder() + .addUserMessage("input") + .model(ChatModel.GPT_4O_MINI) + .responseFormat(StructuredChatOutput::class.java) + .build() + +internal fun blockingServiceOverloads( + service: ChatCompletionService, + params: StructuredChatCompletionCreateParams, +) { + service.create(params) + service.createStreaming(params) +} + +internal fun asyncServiceOverloads( + service: ChatCompletionServiceAsync, + params: StructuredChatCompletionCreateParams, +) { + service.create(params) + service.createStreaming(params) +} +KOTLIN + cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt" <<'KOTLIN' package com.openai.models.responses From 91326396578333979130ed449ad27e851a644122 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 10:47:12 -0700 Subject: [PATCH 18/23] fix(ci): stabilize API compatibility fixtures --- .../excluded-generated-tests.txt | 24 ++ .../compatibility/MultipartCompatibility.kt | 85 +++++++ .../ResponseStreamEventCompatibility.kt | 8 + .../StructuredOutputsCompatibility.kt | 83 +++++++ scripts/detect-breaking-changes | 226 +++++------------- 5 files changed, 254 insertions(+), 172 deletions(-) create mode 100644 openai-java-core/src/apiCompatibility/excluded-generated-tests.txt create mode 100644 openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt create mode 100644 openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/ResponseStreamEventCompatibility.kt create mode 100644 openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt diff --git a/openai-java-core/src/apiCompatibility/excluded-generated-tests.txt b/openai-java-core/src/apiCompatibility/excluded-generated-tests.txt new file mode 100644 index 000000000..7571b3217 --- /dev/null +++ b/openai-java-core/src/apiCompatibility/excluded-generated-tests.txt @@ -0,0 +1,24 @@ +# These baseline tests depend on Kotlin-internal implementation details. Public expressions from +# them live in the consumer fixtures next to this manifest. +openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt +openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt +openai-java-core/src/test/kotlin/com/openai/models/containers/files/FileCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/files/FileCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/images/ImageEditParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt +openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt +openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt +openai-java-core/src/test/kotlin/com/openai/models/skills/SkillCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/skills/versions/VersionCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/uploads/parts/PartCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/videos/VideoCreateCharacterParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/videos/VideoCreateParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/videos/VideoEditParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/videos/VideoExtendParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/models/videos/VideoRemixParamsTest.kt +openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt diff --git a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt new file mode 100644 index 000000000..4fffb94b1 --- /dev/null +++ b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt @@ -0,0 +1,85 @@ +package com.openai.compatibility + +import com.openai.models.audio.AudioModel +import com.openai.models.audio.transcriptions.TranscriptionCreateParams +import com.openai.models.audio.translations.TranslationCreateParams +import com.openai.models.containers.files.FileCreateParams as ContainerFileCreateParams +import com.openai.models.files.FileCreateParams +import com.openai.models.files.FilePurpose +import com.openai.models.images.ImageCreateVariationParams +import com.openai.models.images.ImageEditParams +import com.openai.models.skills.SkillCreateParams +import com.openai.models.skills.versions.VersionCreateParams +import com.openai.models.uploads.parts.PartCreateParams +import com.openai.models.videos.VideoCreateCharacterParams +import com.openai.models.videos.VideoCreateParams +import com.openai.models.videos.VideoEditParams +import com.openai.models.videos.VideoExtendParams +import com.openai.models.videos.VideoRemixParams +import com.openai.models.videos.VideoSeconds +import java.io.InputStream + +internal object MultipartCompatibility { + fun transcription(stream: InputStream): TranscriptionCreateParams = + TranscriptionCreateParams.builder().file(stream).model(AudioModel.GPT_4O_TRANSCRIBE).build() + + fun translation(stream: InputStream): TranslationCreateParams = + TranslationCreateParams.builder().file(stream).model(AudioModel.WHISPER_1).build() + + fun containerFile(stream: InputStream): ContainerFileCreateParams = + ContainerFileCreateParams.builder().containerId("container").file(stream).build() + + fun file(stream: InputStream): FileCreateParams = + FileCreateParams.builder().file(stream).purpose(FilePurpose.ASSISTANTS).build() + + fun imageVariation(stream: InputStream): ImageCreateVariationParams = + ImageCreateVariationParams.builder().image(stream).build() + + fun imageEdit(stream: InputStream): ImageEditParams = + ImageEditParams.builder().image(stream).prompt("prompt").build() + + fun imageEditUnion(stream: InputStream): ImageEditParams.Image = + ImageEditParams.Image.ofInputStream(stream) + + fun imageEditUnionList(streams: List): ImageEditParams.Image = + ImageEditParams.Image.ofInputStreams(streams) + + fun skill(streams: List): SkillCreateParams = + SkillCreateParams.builder().filesOfInputStreams(streams).build() + + fun skillUnion(streams: List): SkillCreateParams.Files = + SkillCreateParams.Files.ofInputStreams(streams) + + fun skillVersion(streams: List): VersionCreateParams = + VersionCreateParams.builder().skillId("skill").filesOfInputStreams(streams).build() + + fun skillVersionUnion(streams: List): VersionCreateParams.Files = + VersionCreateParams.Files.ofInputStreams(streams) + + fun uploadPart(stream: InputStream): PartCreateParams = + PartCreateParams.builder().uploadId("upload").data(stream).build() + + fun videoCharacter(stream: InputStream): VideoCreateCharacterParams = + VideoCreateCharacterParams.builder().name("name").video(stream).build() + + fun videoCreate(stream: InputStream): VideoCreateParams = + VideoCreateParams.builder().prompt("prompt").inputReference(stream).build() + + fun videoCreateUnion(stream: InputStream): VideoCreateParams.InputReference = + VideoCreateParams.InputReference.ofStream(stream) + + fun videoEdit(stream: InputStream): VideoEditParams = + VideoEditParams.builder().prompt("prompt").video(stream).build() + + fun videoEditUnion(stream: InputStream): VideoEditParams.Video = + VideoEditParams.Video.ofInputStream(stream) + + fun videoExtend(stream: InputStream): VideoExtendParams = + VideoExtendParams.builder().prompt("prompt").seconds(VideoSeconds._4).video(stream).build() + + fun videoExtendUnion(stream: InputStream): VideoExtendParams.Video = + VideoExtendParams.Video.ofInputStream(stream) + + fun videoRemix(): VideoRemixParams = + VideoRemixParams.builder().videoId("video").prompt("prompt").build() +} diff --git a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/ResponseStreamEventCompatibility.kt b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/ResponseStreamEventCompatibility.kt new file mode 100644 index 000000000..a855bac7d --- /dev/null +++ b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/ResponseStreamEventCompatibility.kt @@ -0,0 +1,8 @@ +package com.openai.compatibility + +import com.openai.models.responses.ResponseStreamEvent + +internal object ResponseStreamEventCompatibility { + fun outputTextDelta(event: ResponseStreamEvent): String? = + if (event.isOutputTextDelta()) event.asOutputTextDelta().delta() else null +} diff --git a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt new file mode 100644 index 000000000..c18fb8c21 --- /dev/null +++ b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt @@ -0,0 +1,83 @@ +package com.openai.compatibility + +import com.openai.models.ChatModel +import com.openai.models.chat.completions.StructuredChatCompletion +import com.openai.models.chat.completions.StructuredChatCompletionCreateParams +import com.openai.models.responses.ResponseTextConfig +import com.openai.models.responses.StructuredResponse +import com.openai.models.responses.StructuredResponseCreateParams +import com.openai.models.responses.StructuredResponseTextConfig +import com.openai.services.async.ResponseServiceAsync +import com.openai.services.async.chat.ChatCompletionServiceAsync +import com.openai.services.blocking.ResponseService +import com.openai.services.blocking.chat.ChatCompletionService +import java.util.Optional + +internal data class CompatibilityOutput(val value: String) + +internal object StructuredOutputsCompatibility { + fun chatParams(): StructuredChatCompletionCreateParams = + StructuredChatCompletionCreateParams.builder() + .addUserMessage("input") + .model(ChatModel.GPT_4O_MINI) + .responseFormat(CompatibilityOutput::class.java) + .build() + + fun responseParams(): StructuredResponseCreateParams = + StructuredResponseCreateParams.builder() + .input("input") + .model(ChatModel.GPT_4O_MINI) + .text(CompatibilityOutput::class.java) + .build() + + fun responseTextConfig(): StructuredResponseTextConfig = + StructuredResponseTextConfig.builder() + .format(CompatibilityOutput::class.java) + .verbosity(ResponseTextConfig.Verbosity.HIGH) + .build() + + fun chatOutput( + completion: StructuredChatCompletion + ): Optional = completion.choices().first().message().content() + + fun responseOutput(response: StructuredResponse): CompatibilityOutput? = + response + .output() + .firstOrNull { it.isMessage() } + ?.asMessage() + ?.content() + ?.firstOrNull { it.isOutputText() } + ?.asOutputText() + + fun blockingChat( + service: ChatCompletionService, + params: StructuredChatCompletionCreateParams, + ): StructuredChatCompletion { + service.createStreaming(params) + return service.create(params) + } + + fun asyncChat( + service: ChatCompletionServiceAsync, + params: StructuredChatCompletionCreateParams, + ) { + service.create(params) + service.createStreaming(params) + } + + fun blockingResponse( + service: ResponseService, + params: StructuredResponseCreateParams, + ): StructuredResponse { + service.createStreaming(params) + return service.create(params) + } + + fun asyncResponse( + service: ResponseServiceAsync, + params: StructuredResponseCreateParams, + ) { + service.create(params) + service.createStreaming(params) + } +} diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 23d7272ad..f5eed7d89 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -25,27 +25,12 @@ SUPPORT_PATHS=( openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt ) -# Multipart fixtures exercise public parameter builders and union factories, but their generated -# recursive-comparison assertions call the Kotlin-internal `MultipartField.map` helper. Preserve -# each fixture and rewrite only that internal assertion expression. -MULTIPART_FIXTURES=( - openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/containers/files/FileCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/files/FileCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/images/ImageCreateVariationParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/images/ImageEditParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/skills/SkillCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/skills/versions/VersionCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/uploads/parts/PartCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/videos/VideoCreateCharacterParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/videos/VideoCreateParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/videos/VideoEditParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/videos/VideoExtendParamsTest.kt - openai-java-core/src/test/kotlin/com/openai/models/videos/VideoRemixParamsTest.kt -) - COMPATIBILITY_ROOT="openai-java-core/build/api-compatibility-source" +POLICY_PATH="openai-java-core/src/apiCompatibility" +POLICY_ROOT="${COMPATIBILITY_ROOT}/${POLICY_PATH}" +EXCLUSIONS_PATH="${POLICY_ROOT}/excluded-generated-tests.txt" +PUBLIC_FIXTURE_PATH="${POLICY_ROOT}/kotlin" + rm -rf "${COMPATIBILITY_ROOT}" mkdir -p "${COMPATIBILITY_ROOT}" @@ -76,165 +61,58 @@ for PATHSPEC in "${SUPPORT_PATHS[@]}"; do git archive "${BASE_COMMIT}" -- "${PATHSPEC}" | tar -x -C "${COMPATIBILITY_ROOT}" done -# These baseline tests combine public API coverage with Kotlin-internal implementation setup. -# Replace them with consumer-style fixtures that preserve the public expressions without relying on -# internal constructors or helpers. -cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt" <<'KOTLIN' -package com.openai.models.chat.completions - -import com.openai.models.ChatModel -import com.openai.services.async.chat.ChatCompletionServiceAsync -import com.openai.services.blocking.chat.ChatCompletionService - -internal class StructuredChatOutput(val value: String) - -internal fun publicBuilder(): StructuredChatCompletionCreateParams = - StructuredChatCompletionCreateParams.builder() - .addUserMessage("input") - .model(ChatModel.GPT_4O_MINI) - .responseFormat(StructuredChatOutput::class.java) - .build() - -internal fun blockingServiceOverloads( - service: ChatCompletionService, - params: StructuredChatCompletionCreateParams, -) { - service.create(params) - service.createStreaming(params) -} - -internal fun asyncServiceOverloads( - service: ChatCompletionServiceAsync, - params: StructuredChatCompletionCreateParams, -) { - service.create(params) - service.createStreaming(params) -} -KOTLIN - -cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt" <<'KOTLIN' -package com.openai.models.responses - -import com.openai.models.ChatModel -import com.openai.services.async.ResponseServiceAsync -import com.openai.services.blocking.ResponseService - -internal class StructuredResponseOutput(val value: String) - -internal fun publicBuilder(): StructuredResponseCreateParams = - StructuredResponseCreateParams.builder() - .input("input") - .model(ChatModel.GPT_4O_MINI) - .text(StructuredResponseOutput::class.java) - .build() - -internal fun blockingServiceOverloads( - service: ResponseService, - params: StructuredResponseCreateParams, -) { - service.create(params) - service.createStreaming(params) -} - -internal fun asyncServiceOverloads( - service: ResponseServiceAsync, - params: StructuredResponseCreateParams, -) { - service.create(params) - service.createStreaming(params) -} -KOTLIN - -cat > "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/services/ResponseStreamEventValidationTest.kt" <<'KOTLIN' -package com.openai.services - -import com.openai.models.responses.ResponseStreamEvent - -internal class ResponseStreamEventValidationTest { - fun outputTextDelta(event: ResponseStreamEvent): String? = - if (event.isOutputTextDelta()) event.asOutputTextDelta().delta() else null -} -KOTLIN - -# Keep the public API coverage in structured-output fixtures while replacing only references to -# Kotlin-internal constructors and JsonField helpers. -replace_internal_reference() { - local file_path="$1" - local internal_source="$2" - local public_source="$3" +# Compatibility exceptions are policy, not transformations of generated source. Always use the +# policy from the base commit so a proposed SDK change cannot weaken its own compatibility gate. +# The fallback bootstraps the policy on the first commit that introduces it. +if git cat-file -e "${BASE_COMMIT}:${POLICY_PATH}" 2>/dev/null; then + git archive "${BASE_COMMIT}" -- "${POLICY_PATH}" | tar -x -C "${COMPATIBILITY_ROOT}" +else + echo "Baseline has no API compatibility policy; using the proposed policy for bootstrap" + mkdir -p "${POLICY_ROOT}" + cp -R "${POLICY_PATH}/." "${POLICY_ROOT}/" +fi - if [ ! -f "${file_path}" ]; then - echo "Skipping compatibility rewrite; fixture was not restored: ${file_path}" >&2 - return - fi +if [ ! -f "${EXCLUSIONS_PATH}" ]; then + echo "Missing baseline compatibility exclusions: ${EXCLUSIONS_PATH}" >&2 + exit 1 +fi - if ! grep -Fq "${internal_source}" "${file_path}"; then - echo "Skipping compatibility rewrite; internal reference is absent: ${file_path}" >&2 - return +while IFS= read -r PATHSPEC || [ -n "${PATHSPEC}" ]; do + case "${PATHSPEC}" in + ''|\#*) continue ;; + esac + + case "${PATHSPEC}" in + *..*|/*) + echo "Unsafe compatibility exclusion: ${PATHSPEC}" >&2 + exit 1 + ;; + openai-java-core/src/test/kotlin/com/openai/models/*.kt | \ + openai-java-core/src/test/kotlin/com/openai/services/*.kt) ;; + *) + echo "Compatibility exclusion is outside the restored test roots: ${PATHSPEC}" >&2 + exit 1 + ;; + esac + + if [ ! -f "${COMPATIBILITY_ROOT}/${PATHSPEC}" ]; then + echo "Baseline compatibility exclusion does not exist: ${PATHSPEC}" >&2 + exit 1 fi - INTERNAL_SOURCE="${internal_source}" PUBLIC_SOURCE="${public_source}" \ - perl -0pi -e 's/\Q$ENV{INTERNAL_SOURCE}\E/$ENV{PUBLIC_SOURCE}/g' "${file_path}" -} - -for PATHSPEC in "${MULTIPART_FIXTURES[@]}"; do - replace_internal_reference \ - "${COMPATIBILITY_ROOT}/${PATHSPEC}" \ - 'field.map { (it as? ByteArray)?.inputStream() ?: it }' \ - 'field' -done + rm "${COMPATIBILITY_ROOT:?}/${PATHSPEC}" +done < "${EXCLUSIONS_PATH}" -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt" \ - 'StructuredChatCompletionMessage(X::class.java, mockDelegate)' \ - 'mock(StructuredChatCompletionMessage::class.java) as StructuredChatCompletionMessage' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt" \ - 'StructuredChatCompletion.Choice(X::class.java, mockChoiceDelegate)' \ - 'mock(StructuredChatCompletion.Choice::class.java) as StructuredChatCompletion.Choice' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt" \ - 'assertThat(output.getRequired("_choices")[0].rawChoice).isEqualTo(CHOICE)' \ - 'assertThat(output).isEqualTo(input)' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt" \ - 'assertThat(output.getRequired("_message").rawMessage).isEqualTo(MESSAGE)' \ - 'assertThat(output).isEqualTo(input)' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt" \ - 'assertThat(output.getRequired("content")[0].rawContent).isEqualTo(CONTENT)' \ - 'assertThat(output).isEqualTo(input)' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt" \ - 'assertThat(output.getRequired("_output")[0].rawOutputItem).isEqualTo(OUTPUT_ITEM)' \ - 'assertThat(output).isEqualTo(input)' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt" \ - 'import com.openai.core.jsonSchemaFromClass -' \ - '' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt" \ - 'StructuredResponseTextConfig.builder().inject(mockBuilderDelegate)' \ - 'StructuredResponseTextConfig.builder() - .format(X::class.java) - .verbosity(VERBOSITY) - .verbosity(java.util.Optional.of(VERBOSITY)) - .verbosity(com.openai.core.JsonField.of(VERBOSITY)) - .additionalProperties(emptyMap()) - .putAdditionalProperty("key", com.openai.core.JsonValue.from("value")) - .putAllAdditionalProperties(emptyMap()) - .removeAdditionalProperty("key") - .removeAllAdditionalProperties(emptySet())' -replace_internal_reference \ - "${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTextConfigTest.kt" \ - 'jsonSchemaFromClass(X::class.java)' \ - 'mock(ResponseFormatTextJsonSchemaConfig::class.java)' +if ! find "${PUBLIC_FIXTURE_PATH}" -type f -name '*.kt' -print -quit | grep -q .; then + echo "No baseline public compatibility fixtures found in ${PUBLIC_FIXTURE_PATH}" >&2 + exit 1 +fi # Keep the compatibility compilation policy in this detector rather than in the proposed build # file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy # by weakening a source set or task in openai-java-core/build.gradle.kts. -COMPATIBILITY_SOURCE_ROOT="$(pwd)/${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" +GENERATED_TEST_SOURCE_ROOT="$(pwd)/${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" +PUBLIC_FIXTURE_SOURCE_ROOT="$(pwd)/${PUBLIC_FIXTURE_PATH}" COMPATIBILITY_INIT_SCRIPT="$(mktemp)" trap 'rm -f "${COMPATIBILITY_INIT_SCRIPT}"' EXIT @@ -246,7 +124,10 @@ gradle.beforeProject { project -> project.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { def sourceSets = project.extensions.getByName("sourceSets") def compatibility = sourceSets.create("externalApiCompatibility") - compatibility.kotlin.srcDir(System.getenv("COMPATIBILITY_SOURCE_ROOT")) + compatibility.kotlin.srcDirs( + System.getenv("GENERATED_TEST_SOURCE_ROOT"), + System.getenv("PUBLIC_FIXTURE_SOURCE_ROOT"), + ) compatibility.compileClasspath += sourceSets.getByName("main").output project.configurations @@ -261,7 +142,8 @@ gradle.beforeProject { project -> } GRADLE -COMPATIBILITY_SOURCE_ROOT="${COMPATIBILITY_SOURCE_ROOT}" \ +GENERATED_TEST_SOURCE_ROOT="${GENERATED_TEST_SOURCE_ROOT}" \ + PUBLIC_FIXTURE_SOURCE_ROOT="${PUBLIC_FIXTURE_SOURCE_ROOT}" \ ./scripts/gradle \ --init-script "${COMPATIBILITY_INIT_SCRIPT}" \ :openai-java-core:compileExternalApiCompatibilityKotlin \ From 7894338e910f2a81df9e62cd197ab1362f39817e Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 11:05:15 -0700 Subject: [PATCH 19/23] fix(ci): retain codegen branch coverage --- .github/workflows/ci.yml | 1 + scripts/detect-breaking-changes | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef063d0b9..072835527 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - main - next - 'stl/**' + - 'codegen/stl/**' pull_request: branches: - main diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index f5eed7d89..552c40f05 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -87,14 +87,21 @@ while IFS= read -r PATHSPEC || [ -n "${PATHSPEC}" ]; do echo "Unsafe compatibility exclusion: ${PATHSPEC}" >&2 exit 1 ;; - openai-java-core/src/test/kotlin/com/openai/models/*.kt | \ - openai-java-core/src/test/kotlin/com/openai/services/*.kt) ;; - *) - echo "Compatibility exclusion is outside the restored test roots: ${PATHSPEC}" >&2 - exit 1 - ;; esac + IS_RESTORED_TEST=false + for TEST_ROOT in "${TEST_PATHS[@]}"; do + if [[ "${PATHSPEC}" == "${TEST_ROOT}/"* && "${PATHSPEC}" == *.kt ]]; then + IS_RESTORED_TEST=true + break + fi + done + + if [ "${IS_RESTORED_TEST}" != true ]; then + echo "Compatibility exclusion is outside the restored test roots: ${PATHSPEC}" >&2 + exit 1 + fi + if [ ! -f "${COMPATIBILITY_ROOT}/${PATHSPEC}" ]; then echo "Baseline compatibility exclusion does not exist: ${PATHSPEC}" >&2 exit 1 From 112c20fb263ba632cfcbf3f15ac28cb7f9b6ba3d Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 11:31:17 -0700 Subject: [PATCH 20/23] chore(ci): update CodeQL Gradle setup --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 73d193310..16b9dca78 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -31,7 +31,7 @@ jobs: java-version: 21 - name: Set up Gradle - uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d # v4 + uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 - name: Initialize CodeQL uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4 From 2ffbd43543d39b0c3f54fb4d28d5b3a3c2d45cf7 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 11:41:45 -0700 Subject: [PATCH 21/23] fix(ci): harden compatibility policy validation --- .../src/apiCompatibility/dependencies.txt | 9 + .../compatibility/MultipartCompatibility.kt | 9 +- .../StructuredOutputsCompatibility.kt | 31 +++- scripts/detect-breaking-changes | 171 +++++++++++++----- 4 files changed, 171 insertions(+), 49 deletions(-) create mode 100644 openai-java-core/src/apiCompatibility/dependencies.txt diff --git a/openai-java-core/src/apiCompatibility/dependencies.txt b/openai-java-core/src/apiCompatibility/dependencies.txt new file mode 100644 index 000000000..41755e4c6 --- /dev/null +++ b/openai-java-core/src/apiCompatibility/dependencies.txt @@ -0,0 +1,9 @@ +# Baseline-owned compile dependencies for restored generated tests. +org.jetbrains.kotlin:kotlin-stdlib:1.9.20 +org.jetbrains.kotlin:kotlin-test:1.9.20 +org.assertj:assertj-core:3.27.7 +org.junit.jupiter:junit-jupiter-api:5.9.3 +org.junit.jupiter:junit-jupiter-params:5.9.3 +org.mockito:mockito-core:5.14.2 +org.mockito.kotlin:mockito-kotlin:4.1.0 +org.wiremock:wiremock-jetty12:3.13.2 diff --git a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt index 4fffb94b1..6a9ff3be9 100644 --- a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt +++ b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/MultipartCompatibility.kt @@ -21,7 +21,14 @@ import java.io.InputStream internal object MultipartCompatibility { fun transcription(stream: InputStream): TranscriptionCreateParams = - TranscriptionCreateParams.builder().file(stream).model(AudioModel.GPT_4O_TRANSCRIBE).build() + TranscriptionCreateParams.builder() + .file(stream) + .model(AudioModel.GPT_4O_TRANSCRIBE) + .chunkingStrategyAuto() + .build() + + fun transcriptionChunkingStrategy(): TranscriptionCreateParams.ChunkingStrategy = + TranscriptionCreateParams.ChunkingStrategy.ofAuto() fun translation(stream: InputStream): TranslationCreateParams = TranslationCreateParams.builder().file(stream).model(AudioModel.WHISPER_1).build() diff --git a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt index c18fb8c21..b2c14648e 100644 --- a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt +++ b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/StructuredOutputsCompatibility.kt @@ -6,6 +6,7 @@ import com.openai.models.chat.completions.StructuredChatCompletionCreateParams import com.openai.models.responses.ResponseTextConfig import com.openai.models.responses.StructuredResponse import com.openai.models.responses.StructuredResponseCreateParams +import com.openai.models.responses.StructuredResponseOutputMessage import com.openai.models.responses.StructuredResponseTextConfig import com.openai.services.async.ResponseServiceAsync import com.openai.services.async.chat.ChatCompletionServiceAsync @@ -38,7 +39,20 @@ internal object StructuredOutputsCompatibility { fun chatOutput( completion: StructuredChatCompletion - ): Optional = completion.choices().first().message().content() + ): Optional { + completion.validate() + completion.isValid() + return completion.choices().first().message().content() + } + + fun validateChatOutput(completion: StructuredChatCompletion): Boolean { + completion.validate() + val choice = completion.choices().first() + choice.validate() + val message = choice.message() + message.validate() + return completion.isValid() && choice.isValid() && message.isValid() + } fun responseOutput(response: StructuredResponse): CompatibilityOutput? = response @@ -49,6 +63,21 @@ internal object StructuredOutputsCompatibility { ?.firstOrNull { it.isOutputText() } ?.asOutputText() + fun optionalResponseOutput( + content: StructuredResponseOutputMessage.Content + ): Optional = content.outputText() + + fun validateResponseOutput(response: StructuredResponse): Boolean { + response.validate() + val item = response.output().first() + item.validate() + val message = item.asMessage() + message.validate() + val content = message.content().first() + content.validate() + return response.isValid() && item.isValid() && message.isValid() && content.isValid() + } + fun blockingChat( service: ChatCompletionService, params: StructuredChatCompletionCreateParams, diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 552c40f05..fa98632c8 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -28,8 +28,12 @@ SUPPORT_PATHS=( COMPATIBILITY_ROOT="openai-java-core/build/api-compatibility-source" POLICY_PATH="openai-java-core/src/apiCompatibility" POLICY_ROOT="${COMPATIBILITY_ROOT}/${POLICY_PATH}" -EXCLUSIONS_PATH="${POLICY_ROOT}/excluded-generated-tests.txt" -PUBLIC_FIXTURE_PATH="${POLICY_ROOT}/kotlin" +BASELINE_EXCLUSIONS_PATH="${POLICY_ROOT}/excluded-generated-tests.txt" +BASELINE_DEPENDENCIES_PATH="${POLICY_ROOT}/dependencies.txt" +BASELINE_FIXTURE_PATH="${POLICY_ROOT}/kotlin" +PROPOSED_EXCLUSIONS_PATH="${POLICY_PATH}/excluded-generated-tests.txt" +PROPOSED_DEPENDENCIES_PATH="${POLICY_PATH}/dependencies.txt" +PROPOSED_FIXTURE_PATH="${POLICY_PATH}/kotlin" rm -rf "${COMPATIBILITY_ROOT}" mkdir -p "${COMPATIBILITY_ROOT}" @@ -72,54 +76,90 @@ else cp -R "${POLICY_PATH}/." "${POLICY_ROOT}/" fi -if [ ! -f "${EXCLUSIONS_PATH}" ]; then - echo "Missing baseline compatibility exclusions: ${EXCLUSIONS_PATH}" >&2 - exit 1 -fi +validate_exclusions() { + local exclusions_path="$1" + local source_root="$2" + local policy_name="$3" + local remove_exclusions="$4" + + if [ ! -f "${exclusions_path}" ]; then + echo "Missing ${policy_name} compatibility exclusions: ${exclusions_path}" >&2 + exit 1 + fi -while IFS= read -r PATHSPEC || [ -n "${PATHSPEC}" ]; do - case "${PATHSPEC}" in - ''|\#*) continue ;; - esac + while IFS= read -r PATHSPEC || [ -n "${PATHSPEC}" ]; do + case "${PATHSPEC}" in + ''|\#*) continue ;; + esac + + case "${PATHSPEC}" in + *..*|/*) + echo "Unsafe ${policy_name} compatibility exclusion: ${PATHSPEC}" >&2 + exit 1 + ;; + esac + + IS_RESTORED_TEST=false + for TEST_ROOT in "${TEST_PATHS[@]}"; do + if [[ "${PATHSPEC}" == "${TEST_ROOT}/"* && "${PATHSPEC}" == *.kt ]]; then + IS_RESTORED_TEST=true + break + fi + done + + if [ "${IS_RESTORED_TEST}" != true ]; then + echo "${policy_name} compatibility exclusion is outside the test roots: ${PATHSPEC}" >&2 + exit 1 + fi - case "${PATHSPEC}" in - *..*|/*) - echo "Unsafe compatibility exclusion: ${PATHSPEC}" >&2 + if [ ! -f "${source_root}/${PATHSPEC}" ]; then + echo "${policy_name} compatibility exclusion does not exist: ${PATHSPEC}" >&2 exit 1 - ;; - esac - - IS_RESTORED_TEST=false - for TEST_ROOT in "${TEST_PATHS[@]}"; do - if [[ "${PATHSPEC}" == "${TEST_ROOT}/"* && "${PATHSPEC}" == *.kt ]]; then - IS_RESTORED_TEST=true - break fi - done - if [ "${IS_RESTORED_TEST}" != true ]; then - echo "Compatibility exclusion is outside the restored test roots: ${PATHSPEC}" >&2 + if [ "${remove_exclusions}" = true ]; then + rm "${source_root:?}/${PATHSPEC}" + fi + done < "${exclusions_path}" +} + +validate_policy_files() { + local dependencies_path="$1" + local fixture_path="$2" + local policy_name="$3" + + if [ ! -s "${dependencies_path}" ]; then + echo "No ${policy_name} compatibility dependencies found in ${dependencies_path}" >&2 exit 1 fi - if [ ! -f "${COMPATIBILITY_ROOT}/${PATHSPEC}" ]; then - echo "Baseline compatibility exclusion does not exist: ${PATHSPEC}" >&2 + if ! find "${fixture_path}" -type f -name '*.kt' -print -quit | grep -q .; then + echo "No ${policy_name} public compatibility fixtures found in ${fixture_path}" >&2 exit 1 fi +} - rm "${COMPATIBILITY_ROOT:?}/${PATHSPEC}" -done < "${EXCLUSIONS_PATH}" - -if ! find "${PUBLIC_FIXTURE_PATH}" -type f -name '*.kt' -print -quit | grep -q .; then - echo "No baseline public compatibility fixtures found in ${PUBLIC_FIXTURE_PATH}" >&2 - exit 1 -fi +validate_exclusions \ + "${BASELINE_EXCLUSIONS_PATH}" \ + "${COMPATIBILITY_ROOT}" \ + baseline \ + true +validate_exclusions \ + "${PROPOSED_EXCLUSIONS_PATH}" \ + . \ + proposed \ + false +validate_policy_files "${BASELINE_DEPENDENCIES_PATH}" "${BASELINE_FIXTURE_PATH}" baseline +validate_policy_files "${PROPOSED_DEPENDENCIES_PATH}" "${PROPOSED_FIXTURE_PATH}" proposed # Keep the compatibility compilation policy in this detector rather than in the proposed build # file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy # by weakening a source set or task in openai-java-core/build.gradle.kts. GENERATED_TEST_SOURCE_ROOT="$(pwd)/${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" -PUBLIC_FIXTURE_SOURCE_ROOT="$(pwd)/${PUBLIC_FIXTURE_PATH}" +BASELINE_FIXTURE_SOURCE_ROOT="$(pwd)/${BASELINE_FIXTURE_PATH}" +BASELINE_DEPENDENCIES_FILE="$(pwd)/${BASELINE_DEPENDENCIES_PATH}" +PROPOSED_FIXTURE_SOURCE_ROOT="$(pwd)/${PROPOSED_FIXTURE_PATH}" +PROPOSED_DEPENDENCIES_FILE="$(pwd)/${PROPOSED_DEPENDENCIES_PATH}" COMPATIBILITY_INIT_SCRIPT="$(mktemp)" trap 'rm -f "${COMPATIBILITY_INIT_SCRIPT}"' EXIT @@ -130,28 +170,65 @@ gradle.beforeProject { project -> if (project.path == ":openai-java-core") { project.pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { def sourceSets = project.extensions.getByName("sourceSets") - def compatibility = sourceSets.create("externalApiCompatibility") - compatibility.kotlin.srcDirs( + def main = sourceSets.getByName("main") + + def configureCompatibility = { + name, + generatedTestRoot, + fixtureRoot, + dependenciesFile -> + def compatibility = sourceSets.create(name) + if (generatedTestRoot) { + compatibility.kotlin.srcDir(generatedTestRoot) + } + compatibility.kotlin.srcDir(fixtureRoot) + compatibility.compileClasspath += main.output + main.compileClasspath + + def implementation = + project.configurations.getByName( + compatibility.implementationConfigurationName + ) + new File(dependenciesFile).readLines().each { dependency -> + dependency = dependency.trim() + if (dependency && !dependency.startsWith("#")) { + project.dependencies.add(implementation.name, dependency) + } + } + project.dependencies.add( + implementation.name, + project.dependencies.project([path: ":openai-java-client-okhttp"]), + ) + + project.configurations + .getByName(compatibility.compileClasspathConfigurationName) + .attributes + .attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) + } + + configureCompatibility( + "externalApiCompatibility", System.getenv("GENERATED_TEST_SOURCE_ROOT"), - System.getenv("PUBLIC_FIXTURE_SOURCE_ROOT"), + System.getenv("BASELINE_FIXTURE_SOURCE_ROOT"), + System.getenv("BASELINE_DEPENDENCIES_FILE"), + ) + configureCompatibility( + "proposedApiCompatibility", + null, + System.getenv("PROPOSED_FIXTURE_SOURCE_ROOT"), + System.getenv("PROPOSED_DEPENDENCIES_FILE"), ) - compatibility.compileClasspath += sourceSets.getByName("main").output - - project.configurations - .getByName(compatibility.implementationConfigurationName) - .extendsFrom(project.configurations.getByName("testImplementation")) - project.configurations - .getByName(compatibility.compileClasspathConfigurationName) - .attributes - .attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } } } GRADLE GENERATED_TEST_SOURCE_ROOT="${GENERATED_TEST_SOURCE_ROOT}" \ - PUBLIC_FIXTURE_SOURCE_ROOT="${PUBLIC_FIXTURE_SOURCE_ROOT}" \ + BASELINE_FIXTURE_SOURCE_ROOT="${BASELINE_FIXTURE_SOURCE_ROOT}" \ + BASELINE_DEPENDENCIES_FILE="${BASELINE_DEPENDENCIES_FILE}" \ + PROPOSED_FIXTURE_SOURCE_ROOT="${PROPOSED_FIXTURE_SOURCE_ROOT}" \ + PROPOSED_DEPENDENCIES_FILE="${PROPOSED_DEPENDENCIES_FILE}" \ ./scripts/gradle \ --init-script "${COMPATIBILITY_INIT_SCRIPT}" \ :openai-java-core:compileExternalApiCompatibilityKotlin \ + :openai-java-core:compileProposedApiCompatibilityKotlin \ --no-build-cache From f6ef29d661663842b8ed92451526088c1dc956b3 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 12:01:37 -0700 Subject: [PATCH 22/23] fix(ci): validate proposed compatibility sources --- .../UnionFactoriesCompatibility.kt | 82 +++++++++++++++++++ scripts/detect-breaking-changes | 42 ++++++++-- 2 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/UnionFactoriesCompatibility.kt diff --git a/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/UnionFactoriesCompatibility.kt b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/UnionFactoriesCompatibility.kt new file mode 100644 index 000000000..9df28de99 --- /dev/null +++ b/openai-java-core/src/apiCompatibility/kotlin/com/openai/compatibility/UnionFactoriesCompatibility.kt @@ -0,0 +1,82 @@ +package com.openai.compatibility + +import com.openai.models.ChatModel +import com.openai.models.ResponsesModel +import com.openai.models.chat.completions.ChatCompletionAssistantMessageParam +import com.openai.models.chat.completions.ChatCompletionCreateParams +import com.openai.models.chat.completions.ChatCompletionDeveloperMessageParam +import com.openai.models.chat.completions.ChatCompletionFunctionCallOption +import com.openai.models.chat.completions.ChatCompletionFunctionTool +import com.openai.models.chat.completions.ChatCompletionMessageParam +import com.openai.models.chat.completions.ChatCompletionSystemMessageParam +import com.openai.models.chat.completions.ChatCompletionTool +import com.openai.models.chat.completions.ChatCompletionToolChoiceOption +import com.openai.models.chat.completions.ChatCompletionUserMessageParam +import com.openai.models.responses.FunctionTool +import com.openai.models.responses.Response +import com.openai.models.responses.ResponseCreateParams +import com.openai.models.responses.ResponseIncludable +import com.openai.models.responses.ResponseOutputItem +import com.openai.models.responses.ResponseOutputMessage +import com.openai.models.responses.ResponseOutputText +import com.openai.models.responses.ResponseReasoningItem +import com.openai.models.responses.Tool +import com.openai.models.responses.ToolChoiceFunction +import com.openai.models.responses.ToolChoiceTypes + +internal object UnionFactoriesCompatibility { + fun chatMessage(message: ChatCompletionUserMessageParam): ChatCompletionMessageParam = + ChatCompletionMessageParam.ofUser(message) + + fun assistantContent(text: String): ChatCompletionAssistantMessageParam.Content = + ChatCompletionAssistantMessageParam.Content.ofText(text) + + fun developerContent(text: String): ChatCompletionDeveloperMessageParam.Content = + ChatCompletionDeveloperMessageParam.Content.ofText(text) + + fun systemContent(text: String): ChatCompletionSystemMessageParam.Content = + ChatCompletionSystemMessageParam.Content.ofText(text) + + fun userContent(text: String): ChatCompletionUserMessageParam.Content = + ChatCompletionUserMessageParam.Content.ofText(text) + + fun functionCall( + option: ChatCompletionFunctionCallOption + ): ChatCompletionCreateParams.FunctionCall = + ChatCompletionCreateParams.FunctionCall.ofFunctionCallOption(option) + + fun chatTool(function: ChatCompletionFunctionTool): ChatCompletionTool = + ChatCompletionTool.ofFunction(function) + + fun chatToolChoice(auto: ChatCompletionToolChoiceOption.Auto): ChatCompletionToolChoiceOption = + ChatCompletionToolChoiceOption.ofAuto(auto) + + fun responsesModel(model: ChatModel): ResponsesModel = ResponsesModel.ofChat(model) + + fun responseInput(text: String): ResponseCreateParams.Input = + ResponseCreateParams.Input.ofText(text) + + fun responseIncludable(value: String): ResponseIncludable = ResponseIncludable.of(value) + + fun responseConversation(id: String): ResponseCreateParams.Conversation = + ResponseCreateParams.Conversation.ofId(id) + + fun responseToolChoice(types: ToolChoiceTypes): ResponseCreateParams.ToolChoice = + ResponseCreateParams.ToolChoice.ofTypes(types) + + fun responseTool(function: FunctionTool): Tool = Tool.ofFunction(function) + + fun codeInterpreterContainer( + auto: Tool.CodeInterpreter.Container.CodeInterpreterToolAuto + ): Tool.CodeInterpreter.Container = + Tool.CodeInterpreter.Container.ofCodeInterpreterToolAuto(auto) + + fun responseOutputContent(outputText: ResponseOutputText): ResponseOutputMessage.Content = + ResponseOutputMessage.Content.ofOutputText(outputText) + + fun responseResultToolChoice(function: ToolChoiceFunction): Response.ToolChoice = + Response.ToolChoice.ofFunction(function) + + fun responseOutputItem(reasoning: ResponseReasoningItem): ResponseOutputItem = + ResponseOutputItem.ofReasoning(reasoning) +} diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index fa98632c8..6d9d7841c 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -26,6 +26,7 @@ SUPPORT_PATHS=( ) COMPATIBILITY_ROOT="openai-java-core/build/api-compatibility-source" +PROPOSED_COMPATIBILITY_ROOT="${COMPATIBILITY_ROOT}/proposed" POLICY_PATH="openai-java-core/src/apiCompatibility" POLICY_ROOT="${COMPATIBILITY_ROOT}/${POLICY_PATH}" BASELINE_EXCLUSIONS_PATH="${POLICY_ROOT}/excluded-generated-tests.txt" @@ -56,13 +57,36 @@ if [ "${RESTORED_TEST_PATHS}" -eq 0 ]; then exit 1 fi +PROPOSED_TEST_PATHS=0 +for PATHSPEC in "${TEST_PATHS[@]}"; do + if [ ! -d "${PATHSPEC}" ]; then + echo "Skipping proposed test path absent from working tree: ${PATHSPEC}" + continue + fi + + mkdir -p "${PROPOSED_COMPATIBILITY_ROOT}/$(dirname "${PATHSPEC}")" + cp -R "${PATHSPEC}" "${PROPOSED_COMPATIBILITY_ROOT}/$(dirname "${PATHSPEC}")/" + PROPOSED_TEST_PATHS=$((PROPOSED_TEST_PATHS + 1)) +done + +if [ "${PROPOSED_TEST_PATHS}" -eq 0 ]; then + echo "No proposed test paths were found in the working tree" >&2 + exit 1 +fi + for PATHSPEC in "${SUPPORT_PATHS[@]}"; do if ! git cat-file -e "${BASE_COMMIT}:${PATHSPEC}" 2>/dev/null; then echo "Skipping support path absent from base commit: ${PATHSPEC}" - continue + else + git archive "${BASE_COMMIT}" -- "${PATHSPEC}" | tar -x -C "${COMPATIBILITY_ROOT}" fi - git archive "${BASE_COMMIT}" -- "${PATHSPEC}" | tar -x -C "${COMPATIBILITY_ROOT}" + if [ ! -f "${PATHSPEC}" ]; then + echo "Skipping proposed support path absent from working tree: ${PATHSPEC}" + else + mkdir -p "${PROPOSED_COMPATIBILITY_ROOT}/$(dirname "${PATHSPEC}")" + cp "${PATHSPEC}" "${PROPOSED_COMPATIBILITY_ROOT}/${PATHSPEC}" + fi done # Compatibility exceptions are policy, not transformations of generated source. Always use the @@ -146,9 +170,9 @@ validate_exclusions \ true validate_exclusions \ "${PROPOSED_EXCLUSIONS_PATH}" \ - . \ + "${PROPOSED_COMPATIBILITY_ROOT}" \ proposed \ - false + true validate_policy_files "${BASELINE_DEPENDENCIES_PATH}" "${BASELINE_FIXTURE_PATH}" baseline validate_policy_files "${PROPOSED_DEPENDENCIES_PATH}" "${PROPOSED_FIXTURE_PATH}" proposed @@ -156,6 +180,7 @@ validate_policy_files "${PROPOSED_DEPENDENCIES_PATH}" "${PROPOSED_FIXTURE_PATH}" # file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy # by weakening a source set or task in openai-java-core/build.gradle.kts. GENERATED_TEST_SOURCE_ROOT="$(pwd)/${COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" +PROPOSED_GENERATED_TEST_SOURCE_ROOT="$(pwd)/${PROPOSED_COMPATIBILITY_ROOT}/openai-java-core/src/test/kotlin" BASELINE_FIXTURE_SOURCE_ROOT="$(pwd)/${BASELINE_FIXTURE_PATH}" BASELINE_DEPENDENCIES_FILE="$(pwd)/${BASELINE_DEPENDENCIES_PATH}" PROPOSED_FIXTURE_SOURCE_ROOT="$(pwd)/${PROPOSED_FIXTURE_PATH}" @@ -196,7 +221,7 @@ gradle.beforeProject { project -> } project.dependencies.add( implementation.name, - project.dependencies.project([path: ":openai-java-client-okhttp"]), + project.dependencies.project([path: ":openai-java-client-okhttp"]) ) project.configurations @@ -209,13 +234,13 @@ gradle.beforeProject { project -> "externalApiCompatibility", System.getenv("GENERATED_TEST_SOURCE_ROOT"), System.getenv("BASELINE_FIXTURE_SOURCE_ROOT"), - System.getenv("BASELINE_DEPENDENCIES_FILE"), + System.getenv("BASELINE_DEPENDENCIES_FILE") ) configureCompatibility( "proposedApiCompatibility", - null, + System.getenv("PROPOSED_GENERATED_TEST_SOURCE_ROOT"), System.getenv("PROPOSED_FIXTURE_SOURCE_ROOT"), - System.getenv("PROPOSED_DEPENDENCIES_FILE"), + System.getenv("PROPOSED_DEPENDENCIES_FILE") ) } } @@ -223,6 +248,7 @@ gradle.beforeProject { project -> GRADLE GENERATED_TEST_SOURCE_ROOT="${GENERATED_TEST_SOURCE_ROOT}" \ + PROPOSED_GENERATED_TEST_SOURCE_ROOT="${PROPOSED_GENERATED_TEST_SOURCE_ROOT}" \ BASELINE_FIXTURE_SOURCE_ROOT="${BASELINE_FIXTURE_SOURCE_ROOT}" \ BASELINE_DEPENDENCIES_FILE="${BASELINE_DEPENDENCIES_FILE}" \ PROPOSED_FIXTURE_SOURCE_ROOT="${PROPOSED_FIXTURE_SOURCE_ROOT}" \ From 0803a6926fca9d2090919c8ba971f2d63c9adde8 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 24 Jul 2026 12:54:36 -0700 Subject: [PATCH 23/23] fix(ci): preserve structured output API surface --- .../structured-output-public-api.txt | 640 ++++++++++++++++++ scripts/detect-breaking-changes | 131 +++- 2 files changed, 768 insertions(+), 3 deletions(-) create mode 100644 openai-java-core/src/apiCompatibility/structured-output-public-api.txt diff --git a/openai-java-core/src/apiCompatibility/structured-output-public-api.txt b/openai-java-core/src/apiCompatibility/structured-output-public-api.txt new file mode 100644 index 000000000..72b2c009a --- /dev/null +++ b/openai-java-core/src/apiCompatibility/structured-output-public-api.txt @@ -0,0 +1,640 @@ +# Complete public JVM method surface for structured-output types whose generated tests are excluded. +# Format: # +com.openai.models.chat.completions.StructuredChatCompletion#_additionalProperties ()Ljava/util/Map; +com.openai.models.chat.completions.StructuredChatCompletion#_choices ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_created ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_id ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_model ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_moderation ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_object_ ()Lcom/openai/core/JsonValue; +com.openai.models.chat.completions.StructuredChatCompletion#_serviceTier ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_systemFingerprint ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#_usage ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion#choices ()Ljava/util/List; +com.openai.models.chat.completions.StructuredChatCompletion#created ()J +com.openai.models.chat.completions.StructuredChatCompletion#id ()Ljava/lang/String; +com.openai.models.chat.completions.StructuredChatCompletion#isValid ()Z +com.openai.models.chat.completions.StructuredChatCompletion#model ()Ljava/lang/String; +com.openai.models.chat.completions.StructuredChatCompletion#moderation ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletion#rawChatCompletion ()Lcom/openai/models/chat/completions/ChatCompletion; +com.openai.models.chat.completions.StructuredChatCompletion#responseType ()Ljava/lang/Class; +com.openai.models.chat.completions.StructuredChatCompletion#serviceTier ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletion#systemFingerprint ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletion#usage ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletion#validate ()Lcom/openai/models/chat/completions/StructuredChatCompletion; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#_additionalProperties ()Ljava/util/Map; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#_finishReason ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#_index ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#_logprobs ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#_message ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#finishReason ()Lcom/openai/models/chat/completions/ChatCompletion$Choice$FinishReason; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#index ()J +com.openai.models.chat.completions.StructuredChatCompletion$Choice#isValid ()Z +com.openai.models.chat.completions.StructuredChatCompletion$Choice#logprobs ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#message ()Lcom/openai/models/chat/completions/StructuredChatCompletionMessage; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#rawChoice ()Lcom/openai/models/chat/completions/ChatCompletion$Choice; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#responseType ()Ljava/lang/Class; +com.openai.models.chat.completions.StructuredChatCompletion$Choice#validate ()Lcom/openai/models/chat/completions/StructuredChatCompletion$Choice; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams#builder ()Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams#rawParams ()Lcom/openai/models/chat/completions/ChatCompletionCreateParams; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams#responseType ()Ljava/lang/Class; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addAssistantMessage (Lcom/openai/models/chat/completions/ChatCompletionAssistantMessageParam$Content;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addAssistantMessage (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addAssistantMessage (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addAssistantMessageOfArrayOfContentParts (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addCustomTool (Lcom/openai/models/chat/completions/ChatCompletionCustomTool$Custom;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addDeveloperMessage (Lcom/openai/models/chat/completions/ChatCompletionDeveloperMessageParam$Content;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addDeveloperMessage (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addDeveloperMessageOfArrayOfContentParts (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addFunction (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Function;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addFunctionTool (Lcom/openai/models/FunctionDefinition;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionAssistantMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionDeveloperMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionFunctionMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionMessage;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionSystemMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionToolMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addMessage (Lcom/openai/models/chat/completions/ChatCompletionUserMessageParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addModality (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Modality;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addSystemMessage (Lcom/openai/models/chat/completions/ChatCompletionSystemMessageParam$Content;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addSystemMessage (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addSystemMessageOfArrayOfContentParts (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addTool (Lcom/openai/models/chat/completions/ChatCompletionCustomTool;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addTool (Lcom/openai/models/chat/completions/ChatCompletionFunctionTool;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addTool (Lcom/openai/models/chat/completions/ChatCompletionTool;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addTool (Ljava/lang/Class;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addTool (Ljava/lang/Class;Lcom/openai/core/JsonSchemaLocalValidation;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addUserMessage (Lcom/openai/models/chat/completions/ChatCompletionUserMessageParam$Content;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addUserMessage (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#addUserMessageOfArrayOfContentParts (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#additionalBodyProperties (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#additionalHeaders (Lcom/openai/core/http/Headers;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#additionalHeaders (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#additionalQueryParams (Lcom/openai/core/http/QueryParams;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#additionalQueryParams (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#audio (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#audio (Lcom/openai/models/chat/completions/ChatCompletionAudioParam;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#audio (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#body (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Body;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#build ()Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#frequencyPenalty (D)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#frequencyPenalty (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#frequencyPenalty (Ljava/lang/Double;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#frequencyPenalty (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#functionCall (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#functionCall (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$FunctionCall$FunctionCallMode;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#functionCall (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$FunctionCall;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#functionCall (Lcom/openai/models/chat/completions/ChatCompletionFunctionCallOption;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#functions (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#functions (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#jsonSchemaResponseFormat (Lcom/openai/models/ResponseFormatJsonSchema$JsonSchema;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logitBias (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logitBias (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$LogitBias;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logitBias (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logprobs (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logprobs (Ljava/lang/Boolean;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logprobs (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#logprobs (Z)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxCompletionTokens (J)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxCompletionTokens (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxCompletionTokens (Ljava/lang/Long;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxCompletionTokens (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxTokens (J)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxTokens (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxTokens (Ljava/lang/Long;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#maxTokens (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#messages (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#messages (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#metadata (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#metadata (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Metadata;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#metadata (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#modalities (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#modalities (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#modalities (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#model (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#model (Lcom/openai/models/ChatModel;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#model (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#moderation (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#moderation (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Moderation;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#moderation (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#n (J)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#n (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#n (Ljava/lang/Long;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#n (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#parallelToolCalls (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#parallelToolCalls (Z)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#prediction (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#prediction (Lcom/openai/models/chat/completions/ChatCompletionPredictionContent;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#prediction (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#presencePenalty (D)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#presencePenalty (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#presencePenalty (Ljava/lang/Double;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#presencePenalty (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheKey (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheKey (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheKey (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheOptions (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheOptions (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$PromptCacheOptions;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheRetention (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheRetention (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$PromptCacheRetention;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#promptCacheRetention (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAdditionalBodyProperty (Ljava/lang/String;Lcom/openai/core/JsonValue;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAdditionalHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAdditionalHeaders (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAdditionalQueryParam (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAdditionalQueryParams (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAllAdditionalBodyProperties (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAllAdditionalHeaders (Lcom/openai/core/http/Headers;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAllAdditionalHeaders (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAllAdditionalQueryParams (Lcom/openai/core/http/QueryParams;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#putAllAdditionalQueryParams (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#reasoningEffort (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#reasoningEffort (Lcom/openai/models/ReasoningEffort;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#reasoningEffort (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#removeAdditionalBodyProperty (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#removeAdditionalHeaders (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#removeAdditionalQueryParams (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#removeAllAdditionalBodyProperties (Ljava/util/Set;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#removeAllAdditionalHeaders (Ljava/util/Set;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#removeAllAdditionalQueryParams (Ljava/util/Set;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAdditionalHeaders (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAdditionalHeaders (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAdditionalQueryParams (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAdditionalQueryParams (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAllAdditionalHeaders (Lcom/openai/core/http/Headers;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAllAdditionalHeaders (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAllAdditionalQueryParams (Lcom/openai/core/http/QueryParams;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#replaceAllAdditionalQueryParams (Ljava/util/Map;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#responseFormat (Ljava/lang/Class;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#responseFormat (Ljava/lang/Class;Lcom/openai/core/JsonSchemaLocalValidation;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#safetyIdentifier (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#safetyIdentifier (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#safetyIdentifier (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#seed (J)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#seed (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#seed (Ljava/lang/Long;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#seed (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#serviceTier (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#serviceTier (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$ServiceTier;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#serviceTier (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#stop (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#stop (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Stop;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#stop (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#stop (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#stopOfStrings (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#store (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#store (Ljava/lang/Boolean;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#store (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#store (Z)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#streamOptions (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#streamOptions (Lcom/openai/models/chat/completions/ChatCompletionStreamOptions;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#streamOptions (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#temperature (D)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#temperature (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#temperature (Ljava/lang/Double;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#temperature (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#toolChoice (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#toolChoice (Lcom/openai/models/chat/completions/ChatCompletionAllowedToolChoice;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#toolChoice (Lcom/openai/models/chat/completions/ChatCompletionNamedToolChoice;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#toolChoice (Lcom/openai/models/chat/completions/ChatCompletionNamedToolChoiceCustom;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#toolChoice (Lcom/openai/models/chat/completions/ChatCompletionToolChoiceOption$Auto;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#toolChoice (Lcom/openai/models/chat/completions/ChatCompletionToolChoiceOption;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#tools (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#tools (Ljava/util/List;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topLogprobs (J)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topLogprobs (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topLogprobs (Ljava/lang/Long;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topLogprobs (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topP (D)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topP (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topP (Ljava/lang/Double;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#topP (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#user (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#user (Ljava/lang/String;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#verbosity (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#verbosity (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$Verbosity;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#verbosity (Ljava/util/Optional;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#webSearchOptions (Lcom/openai/core/JsonField;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionCreateParams$Builder#webSearchOptions (Lcom/openai/models/chat/completions/ChatCompletionCreateParams$WebSearchOptions;)Lcom/openai/models/chat/completions/StructuredChatCompletionCreateParams$Builder; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_additionalProperties ()Ljava/util/Map; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_annotations ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_audio ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_content ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_functionCall ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_refusal ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_role ()Lcom/openai/core/JsonValue; +com.openai.models.chat.completions.StructuredChatCompletionMessage#_toolCalls ()Lcom/openai/core/JsonField; +com.openai.models.chat.completions.StructuredChatCompletionMessage#annotations ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletionMessage#audio ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletionMessage#content ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletionMessage#functionCall ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletionMessage#isValid ()Z +com.openai.models.chat.completions.StructuredChatCompletionMessage#rawMessage ()Lcom/openai/models/chat/completions/ChatCompletionMessage; +com.openai.models.chat.completions.StructuredChatCompletionMessage#refusal ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletionMessage#responseType ()Ljava/lang/Class; +com.openai.models.chat.completions.StructuredChatCompletionMessage#toolCalls ()Ljava/util/Optional; +com.openai.models.chat.completions.StructuredChatCompletionMessage#validate ()Lcom/openai/models/chat/completions/ChatCompletionMessage; +com.openai.models.responses.StructuredResponse#_additionalProperties ()Ljava/util/Map; +com.openai.models.responses.StructuredResponse#_background ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_completedAt ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_conversation ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_createdAt ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_error ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_id ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_incompleteDetails ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_instructions ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_maxOutputTokens ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_maxToolCalls ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_metadata ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_model ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_moderation ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_object_ ()Lcom/openai/core/JsonValue; +com.openai.models.responses.StructuredResponse#_output ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_parallelToolCalls ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_previousResponseId ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_prompt ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_promptCacheKey ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_promptCacheOptions ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_promptCacheRetention ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_reasoning ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_safetyIdentifier ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_serviceTier ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_status ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_temperature ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_text ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_toolChoice ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_tools ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_topLogprobs ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_topP ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_truncation ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_usage ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#_user ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponse#background ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#completedAt ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#conversation ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#createdAt ()D +com.openai.models.responses.StructuredResponse#error ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#id ()Ljava/lang/String; +com.openai.models.responses.StructuredResponse#incompleteDetails ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#instructions ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#isValid ()Z +com.openai.models.responses.StructuredResponse#maxOutputTokens ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#maxToolCalls ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#metadata ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#model ()Lcom/openai/models/ResponsesModel; +com.openai.models.responses.StructuredResponse#moderation ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#output ()Ljava/util/List; +com.openai.models.responses.StructuredResponse#parallelToolCalls ()Z +com.openai.models.responses.StructuredResponse#previousResponseId ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#prompt ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#promptCacheKey ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#promptCacheOptions ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#promptCacheRetention ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#rawResponse ()Lcom/openai/models/responses/Response; +com.openai.models.responses.StructuredResponse#reasoning ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#responseType ()Ljava/lang/Class; +com.openai.models.responses.StructuredResponse#safetyIdentifier ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#serviceTier ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#status ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#temperature ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#text ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#toolChoice ()Lcom/openai/models/responses/Response$ToolChoice; +com.openai.models.responses.StructuredResponse#tools ()Ljava/util/List; +com.openai.models.responses.StructuredResponse#topLogprobs ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#topP ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#truncation ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#usage ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#user ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponse#validate ()Lcom/openai/models/responses/StructuredResponse; +com.openai.models.responses.StructuredResponseCreateParams#builder ()Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams#rawParams ()Lcom/openai/models/responses/ResponseCreateParams; +com.openai.models.responses.StructuredResponseCreateParams#responseType ()Ljava/lang/Class; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addCodeInterpreterTool (Lcom/openai/models/responses/Tool$CodeInterpreter$Container$CodeInterpreterToolAuto;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addCodeInterpreterTool (Lcom/openai/models/responses/Tool$CodeInterpreter$Container;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addCodeInterpreterTool (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addContextManagement (Lcom/openai/models/responses/ResponseCreateParams$ContextManagement;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addCustomTool (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addFileSearchTool (Ljava/util/List;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addInclude (Lcom/openai/models/responses/ResponseIncludable;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addMcpTool (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/ApplyPatchTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/ComputerTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/ComputerUsePreviewTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/CustomTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/FileSearchTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/FunctionShellTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/FunctionTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/NamespaceTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/Tool$CodeInterpreter;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/Tool$ImageGeneration;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/Tool$Mcp;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/Tool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/ToolSearchTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/WebSearchPreviewTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Lcom/openai/models/responses/WebSearchTool;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Ljava/lang/Class;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addTool (Ljava/lang/Class;Lcom/openai/core/JsonSchemaLocalValidation;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addToolLocalShell ()Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#addToolProgrammaticToolCalling ()Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#additionalBodyProperties (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#additionalHeaders (Lcom/openai/core/http/Headers;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#additionalHeaders (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#additionalQueryParams (Lcom/openai/core/http/QueryParams;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#additionalQueryParams (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#background (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#background (Ljava/lang/Boolean;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#background (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#background (Z)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#build ()Lcom/openai/models/responses/StructuredResponseCreateParams; +com.openai.models.responses.StructuredResponseCreateParams$Builder#contextManagement (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#contextManagement (Ljava/util/List;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#contextManagement (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#conversation (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#conversation (Lcom/openai/models/responses/ResponseConversationParam;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#conversation (Lcom/openai/models/responses/ResponseCreateParams$Conversation;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#conversation (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#conversation (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#include (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#include (Ljava/util/List;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#include (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#input (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#input (Lcom/openai/models/responses/ResponseCreateParams$Input;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#input (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#inputOfResponse (Ljava/util/List;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#instructions (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#instructions (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#instructions (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxOutputTokens (J)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxOutputTokens (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxOutputTokens (Ljava/lang/Long;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxOutputTokens (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxToolCalls (J)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxToolCalls (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxToolCalls (Ljava/lang/Long;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#maxToolCalls (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#metadata (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#metadata (Lcom/openai/models/responses/ResponseCreateParams$Metadata;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#metadata (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#model (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#model (Lcom/openai/models/ChatModel;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#model (Lcom/openai/models/ResponsesModel$ResponsesOnlyModel;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#model (Lcom/openai/models/ResponsesModel;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#model (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#moderation (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#moderation (Lcom/openai/models/responses/ResponseCreateParams$Moderation;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#moderation (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#parallelToolCalls (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#parallelToolCalls (Ljava/lang/Boolean;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#parallelToolCalls (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#parallelToolCalls (Z)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#previousResponseId (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#previousResponseId (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#previousResponseId (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#prompt (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#prompt (Lcom/openai/models/responses/ResponsePrompt;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#prompt (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheKey (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheKey (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheKey (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheOptions (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheOptions (Lcom/openai/models/responses/ResponseCreateParams$PromptCacheOptions;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheRetention (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheRetention (Lcom/openai/models/responses/ResponseCreateParams$PromptCacheRetention;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#promptCacheRetention (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAdditionalBodyProperty (Ljava/lang/String;Lcom/openai/core/JsonValue;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAdditionalHeader (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAdditionalHeaders (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAdditionalQueryParam (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAdditionalQueryParams (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAllAdditionalBodyProperties (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAllAdditionalHeaders (Lcom/openai/core/http/Headers;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAllAdditionalHeaders (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAllAdditionalQueryParams (Lcom/openai/core/http/QueryParams;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#putAllAdditionalQueryParams (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#reasoning (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#reasoning (Lcom/openai/models/Reasoning;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#reasoning (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#removeAdditionalBodyProperty (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#removeAdditionalHeaders (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#removeAdditionalQueryParams (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#removeAllAdditionalBodyProperties (Ljava/util/Set;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#removeAllAdditionalHeaders (Ljava/util/Set;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#removeAllAdditionalQueryParams (Ljava/util/Set;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAdditionalHeaders (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAdditionalHeaders (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAdditionalQueryParams (Ljava/lang/String;Ljava/lang/Iterable;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAdditionalQueryParams (Ljava/lang/String;Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAllAdditionalHeaders (Lcom/openai/core/http/Headers;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAllAdditionalHeaders (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAllAdditionalQueryParams (Lcom/openai/core/http/QueryParams;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#replaceAllAdditionalQueryParams (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#safetyIdentifier (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#safetyIdentifier (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#safetyIdentifier (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#serviceTier (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#serviceTier (Lcom/openai/models/responses/ResponseCreateParams$ServiceTier;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#serviceTier (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#store (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#store (Ljava/lang/Boolean;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#store (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#store (Z)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#streamOptions (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#streamOptions (Lcom/openai/models/responses/ResponseCreateParams$StreamOptions;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#streamOptions (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#temperature (D)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#temperature (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#temperature (Ljava/lang/Double;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#temperature (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#text (Lcom/openai/models/responses/StructuredResponseTextConfig;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#text (Ljava/lang/Class;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#text (Ljava/lang/Class;Lcom/openai/core/JsonSchemaLocalValidation;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ResponseCreateParams$ToolChoice;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceAllowed;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceApplyPatch;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceCustom;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceFunction;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceMcp;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceOptions;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceShell;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoice (Lcom/openai/models/responses/ToolChoiceTypes;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#toolChoiceSpecificProgrammaticToolCallingParam ()Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#tools (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#tools (Ljava/util/List;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topLogprobs (J)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topLogprobs (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topLogprobs (Ljava/lang/Long;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topLogprobs (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topP (D)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topP (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topP (Ljava/lang/Double;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#topP (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#truncation (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#truncation (Lcom/openai/models/responses/ResponseCreateParams$Truncation;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#truncation (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#user (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseCreateParams$Builder#user (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseCreateParams$Builder; +com.openai.models.responses.StructuredResponseOutputItem#_json ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#accept (Lcom/openai/models/responses/StructuredResponseOutputItem$Visitor;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem#additionalTools ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#applyPatchCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#applyPatchCallOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#asAdditionalTools ()Lcom/openai/models/responses/ResponseOutputItem$AdditionalTools; +com.openai.models.responses.StructuredResponseOutputItem#asApplyPatchCall ()Lcom/openai/models/responses/ResponseApplyPatchToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asApplyPatchCallOutput ()Lcom/openai/models/responses/ResponseApplyPatchToolCallOutput; +com.openai.models.responses.StructuredResponseOutputItem#asCodeInterpreterCall ()Lcom/openai/models/responses/ResponseCodeInterpreterToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asCompaction ()Lcom/openai/models/responses/ResponseCompactionItem; +com.openai.models.responses.StructuredResponseOutputItem#asComputerCall ()Lcom/openai/models/responses/ResponseComputerToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asComputerCallOutput ()Lcom/openai/models/responses/ResponseComputerToolCallOutputItem; +com.openai.models.responses.StructuredResponseOutputItem#asCustomToolCall ()Lcom/openai/models/responses/ResponseCustomToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asCustomToolCallOutput ()Lcom/openai/models/responses/ResponseCustomToolCallOutputItem; +com.openai.models.responses.StructuredResponseOutputItem#asFileSearchCall ()Lcom/openai/models/responses/ResponseFileSearchToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asFunctionCall ()Lcom/openai/models/responses/ResponseFunctionToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asFunctionCallOutput ()Lcom/openai/models/responses/ResponseFunctionToolCallOutputItem; +com.openai.models.responses.StructuredResponseOutputItem#asImageGenerationCall ()Lcom/openai/models/responses/ResponseOutputItem$ImageGenerationCall; +com.openai.models.responses.StructuredResponseOutputItem#asLocalShellCall ()Lcom/openai/models/responses/ResponseOutputItem$LocalShellCall; +com.openai.models.responses.StructuredResponseOutputItem#asLocalShellCallOutput ()Lcom/openai/models/responses/ResponseOutputItem$LocalShellCallOutput; +com.openai.models.responses.StructuredResponseOutputItem#asMcpApprovalRequest ()Lcom/openai/models/responses/ResponseOutputItem$McpApprovalRequest; +com.openai.models.responses.StructuredResponseOutputItem#asMcpApprovalResponse ()Lcom/openai/models/responses/ResponseOutputItem$McpApprovalResponse; +com.openai.models.responses.StructuredResponseOutputItem#asMcpCall ()Lcom/openai/models/responses/ResponseOutputItem$McpCall; +com.openai.models.responses.StructuredResponseOutputItem#asMcpListTools ()Lcom/openai/models/responses/ResponseOutputItem$McpListTools; +com.openai.models.responses.StructuredResponseOutputItem#asMessage ()Lcom/openai/models/responses/StructuredResponseOutputMessage; +com.openai.models.responses.StructuredResponseOutputItem#asProgram ()Lcom/openai/models/responses/ResponseOutputItem$Program; +com.openai.models.responses.StructuredResponseOutputItem#asProgramOutput ()Lcom/openai/models/responses/ResponseOutputItem$ProgramOutput; +com.openai.models.responses.StructuredResponseOutputItem#asReasoning ()Lcom/openai/models/responses/ResponseReasoningItem; +com.openai.models.responses.StructuredResponseOutputItem#asShellCall ()Lcom/openai/models/responses/ResponseFunctionShellToolCall; +com.openai.models.responses.StructuredResponseOutputItem#asShellCallOutput ()Lcom/openai/models/responses/ResponseFunctionShellToolCallOutput; +com.openai.models.responses.StructuredResponseOutputItem#asToolSearchCall ()Lcom/openai/models/responses/ResponseToolSearchCall; +com.openai.models.responses.StructuredResponseOutputItem#asToolSearchOutput ()Lcom/openai/models/responses/ResponseToolSearchOutputItem; +com.openai.models.responses.StructuredResponseOutputItem#asWebSearchCall ()Lcom/openai/models/responses/ResponseFunctionWebSearch; +com.openai.models.responses.StructuredResponseOutputItem#codeInterpreterCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#compaction ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#computerCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#computerCallOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#customToolCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#customToolCallOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#fileSearchCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#functionCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#functionCallOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#imageGenerationCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#isAdditionalTools ()Z +com.openai.models.responses.StructuredResponseOutputItem#isApplyPatchCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isApplyPatchCallOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isCodeInterpreterCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isCompaction ()Z +com.openai.models.responses.StructuredResponseOutputItem#isComputerCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isComputerCallOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isCustomToolCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isCustomToolCallOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isFileSearchCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isFunctionCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isFunctionCallOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isImageGenerationCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isLocalShellCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isLocalShellCallOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isMcpApprovalRequest ()Z +com.openai.models.responses.StructuredResponseOutputItem#isMcpApprovalResponse ()Z +com.openai.models.responses.StructuredResponseOutputItem#isMcpCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isMcpListTools ()Z +com.openai.models.responses.StructuredResponseOutputItem#isMessage ()Z +com.openai.models.responses.StructuredResponseOutputItem#isProgram ()Z +com.openai.models.responses.StructuredResponseOutputItem#isProgramOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isReasoning ()Z +com.openai.models.responses.StructuredResponseOutputItem#isShellCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isShellCallOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isToolSearchCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#isToolSearchOutput ()Z +com.openai.models.responses.StructuredResponseOutputItem#isValid ()Z +com.openai.models.responses.StructuredResponseOutputItem#isWebSearchCall ()Z +com.openai.models.responses.StructuredResponseOutputItem#localShellCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#localShellCallOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#mcpApprovalRequest ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#mcpApprovalResponse ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#mcpCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#mcpListTools ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#message ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#program ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#programOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#rawOutputItem ()Lcom/openai/models/responses/ResponseOutputItem; +com.openai.models.responses.StructuredResponseOutputItem#reasoning ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#responseType ()Ljava/lang/Class; +com.openai.models.responses.StructuredResponseOutputItem#shellCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#shellCallOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#toolSearchCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#toolSearchOutput ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem#validate ()Lcom/openai/models/responses/StructuredResponseOutputItem; +com.openai.models.responses.StructuredResponseOutputItem#webSearchCall ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#unknown (Lcom/openai/core/JsonValue;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitAdditionalTools (Lcom/openai/models/responses/ResponseOutputItem$AdditionalTools;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitApplyPatchCall (Lcom/openai/models/responses/ResponseApplyPatchToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitApplyPatchCallOutput (Lcom/openai/models/responses/ResponseApplyPatchToolCallOutput;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitCodeInterpreterCall (Lcom/openai/models/responses/ResponseCodeInterpreterToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitCompaction (Lcom/openai/models/responses/ResponseCompactionItem;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitComputerCall (Lcom/openai/models/responses/ResponseComputerToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitComputerCallOutput (Lcom/openai/models/responses/ResponseComputerToolCallOutputItem;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitCustomToolCall (Lcom/openai/models/responses/ResponseCustomToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitCustomToolCallOutput (Lcom/openai/models/responses/ResponseCustomToolCallOutputItem;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitFileSearchCall (Lcom/openai/models/responses/ResponseFileSearchToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitFunctionCall (Lcom/openai/models/responses/ResponseFunctionToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitFunctionCallOutput (Lcom/openai/models/responses/ResponseFunctionToolCallOutputItem;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitImageGenerationCall (Lcom/openai/models/responses/ResponseOutputItem$ImageGenerationCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitLocalShellCall (Lcom/openai/models/responses/ResponseOutputItem$LocalShellCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitLocalShellCallOutput (Lcom/openai/models/responses/ResponseOutputItem$LocalShellCallOutput;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitMcpApprovalRequest (Lcom/openai/models/responses/ResponseOutputItem$McpApprovalRequest;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitMcpApprovalResponse (Lcom/openai/models/responses/ResponseOutputItem$McpApprovalResponse;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitMcpCall (Lcom/openai/models/responses/ResponseOutputItem$McpCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitMcpListTools (Lcom/openai/models/responses/ResponseOutputItem$McpListTools;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitMessage (Lcom/openai/models/responses/StructuredResponseOutputMessage;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitProgram (Lcom/openai/models/responses/ResponseOutputItem$Program;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitProgramOutput (Lcom/openai/models/responses/ResponseOutputItem$ProgramOutput;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitReasoning (Lcom/openai/models/responses/ResponseReasoningItem;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitShellCall (Lcom/openai/models/responses/ResponseFunctionShellToolCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitShellCallOutput (Lcom/openai/models/responses/ResponseFunctionShellToolCallOutput;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitToolSearchCall (Lcom/openai/models/responses/ResponseToolSearchCall;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitToolSearchOutput (Lcom/openai/models/responses/ResponseToolSearchOutputItem;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputItem$Visitor#visitWebSearchCall (Lcom/openai/models/responses/ResponseFunctionWebSearch;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputMessage#_additionalProperties ()Ljava/util/Map; +com.openai.models.responses.StructuredResponseOutputMessage#_content ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponseOutputMessage#_id ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponseOutputMessage#_phase ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponseOutputMessage#_role ()Lcom/openai/core/JsonValue; +com.openai.models.responses.StructuredResponseOutputMessage#_status ()Lcom/openai/core/JsonField; +com.openai.models.responses.StructuredResponseOutputMessage#_type ()Lcom/openai/core/JsonValue; +com.openai.models.responses.StructuredResponseOutputMessage#content ()Ljava/util/List; +com.openai.models.responses.StructuredResponseOutputMessage#id ()Ljava/lang/String; +com.openai.models.responses.StructuredResponseOutputMessage#isValid ()Z +com.openai.models.responses.StructuredResponseOutputMessage#phase ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputMessage#rawMessage ()Lcom/openai/models/responses/ResponseOutputMessage; +com.openai.models.responses.StructuredResponseOutputMessage#responseType ()Ljava/lang/Class; +com.openai.models.responses.StructuredResponseOutputMessage#status ()Lcom/openai/models/responses/ResponseOutputMessage$Status; +com.openai.models.responses.StructuredResponseOutputMessage#validate ()Lcom/openai/models/responses/StructuredResponseOutputMessage; +com.openai.models.responses.StructuredResponseOutputMessage$Content#_json ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputMessage$Content#accept (Lcom/openai/models/responses/StructuredResponseOutputMessage$Content$Visitor;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputMessage$Content#asOutputText ()Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputMessage$Content#asRefusal ()Lcom/openai/models/responses/ResponseOutputRefusal; +com.openai.models.responses.StructuredResponseOutputMessage$Content#isOutputText ()Z +com.openai.models.responses.StructuredResponseOutputMessage$Content#isRefusal ()Z +com.openai.models.responses.StructuredResponseOutputMessage$Content#isValid ()Z +com.openai.models.responses.StructuredResponseOutputMessage$Content#outputText ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputMessage$Content#rawContent ()Lcom/openai/models/responses/ResponseOutputMessage$Content; +com.openai.models.responses.StructuredResponseOutputMessage$Content#refusal ()Ljava/util/Optional; +com.openai.models.responses.StructuredResponseOutputMessage$Content#responseType ()Ljava/lang/Class; +com.openai.models.responses.StructuredResponseOutputMessage$Content#validate ()Lcom/openai/models/responses/StructuredResponseOutputMessage$Content; +com.openai.models.responses.StructuredResponseOutputMessage$Content$Visitor#unknown (Lcom/openai/core/JsonValue;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputMessage$Content$Visitor#visitOutputText (Ljava/lang/Object;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseOutputMessage$Content$Visitor#visitRefusal (Lcom/openai/models/responses/ResponseOutputRefusal;)Ljava/lang/Object; +com.openai.models.responses.StructuredResponseTextConfig#builder ()Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig#rawConfig ()Lcom/openai/models/responses/ResponseTextConfig; +com.openai.models.responses.StructuredResponseTextConfig#responseType ()Ljava/lang/Class; +com.openai.models.responses.StructuredResponseTextConfig$Builder#additionalProperties (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#build ()Lcom/openai/models/responses/StructuredResponseTextConfig; +com.openai.models.responses.StructuredResponseTextConfig$Builder#format (Ljava/lang/Class;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#format (Ljava/lang/Class;Lcom/openai/core/JsonSchemaLocalValidation;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#putAdditionalProperty (Ljava/lang/String;Lcom/openai/core/JsonValue;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#putAllAdditionalProperties (Ljava/util/Map;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#removeAdditionalProperty (Ljava/lang/String;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#removeAllAdditionalProperties (Ljava/util/Set;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#verbosity (Lcom/openai/core/JsonField;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#verbosity (Lcom/openai/models/responses/ResponseTextConfig$Verbosity;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; +com.openai.models.responses.StructuredResponseTextConfig$Builder#verbosity (Ljava/util/Optional;)Lcom/openai/models/responses/StructuredResponseTextConfig$Builder; diff --git a/scripts/detect-breaking-changes b/scripts/detect-breaking-changes index 6d9d7841c..e0fae15cd 100755 --- a/scripts/detect-breaking-changes +++ b/scripts/detect-breaking-changes @@ -31,9 +31,11 @@ POLICY_PATH="openai-java-core/src/apiCompatibility" POLICY_ROOT="${COMPATIBILITY_ROOT}/${POLICY_PATH}" BASELINE_EXCLUSIONS_PATH="${POLICY_ROOT}/excluded-generated-tests.txt" BASELINE_DEPENDENCIES_PATH="${POLICY_ROOT}/dependencies.txt" +BASELINE_PUBLIC_API_PATH="${POLICY_ROOT}/structured-output-public-api.txt" BASELINE_FIXTURE_PATH="${POLICY_ROOT}/kotlin" PROPOSED_EXCLUSIONS_PATH="${POLICY_PATH}/excluded-generated-tests.txt" PROPOSED_DEPENDENCIES_PATH="${POLICY_PATH}/dependencies.txt" +PROPOSED_PUBLIC_API_PATH="${POLICY_PATH}/structured-output-public-api.txt" PROPOSED_FIXTURE_PATH="${POLICY_PATH}/kotlin" rm -rf "${COMPATIBILITY_ROOT}" @@ -150,7 +152,8 @@ validate_exclusions() { validate_policy_files() { local dependencies_path="$1" local fixture_path="$2" - local policy_name="$3" + local public_api_path="$3" + local policy_name="$4" if [ ! -s "${dependencies_path}" ]; then echo "No ${policy_name} compatibility dependencies found in ${dependencies_path}" >&2 @@ -161,6 +164,11 @@ validate_policy_files() { echo "No ${policy_name} public compatibility fixtures found in ${fixture_path}" >&2 exit 1 fi + + if [ ! -s "${public_api_path}" ]; then + echo "No ${policy_name} structured-output API signatures found in ${public_api_path}" >&2 + exit 1 + fi } validate_exclusions \ @@ -173,8 +181,16 @@ validate_exclusions \ "${PROPOSED_COMPATIBILITY_ROOT}" \ proposed \ true -validate_policy_files "${BASELINE_DEPENDENCIES_PATH}" "${BASELINE_FIXTURE_PATH}" baseline -validate_policy_files "${PROPOSED_DEPENDENCIES_PATH}" "${PROPOSED_FIXTURE_PATH}" proposed +validate_policy_files \ + "${BASELINE_DEPENDENCIES_PATH}" \ + "${BASELINE_FIXTURE_PATH}" \ + "${BASELINE_PUBLIC_API_PATH}" \ + baseline +validate_policy_files \ + "${PROPOSED_DEPENDENCIES_PATH}" \ + "${PROPOSED_FIXTURE_PATH}" \ + "${PROPOSED_PUBLIC_API_PATH}" \ + proposed # Keep the compatibility compilation policy in this detector rather than in the proposed build # file. CI also runs the detector from the base commit, so a PR cannot bypass that baseline policy @@ -258,3 +274,112 @@ GENERATED_TEST_SOURCE_ROOT="${GENERATED_TEST_SOURCE_ROOT}" \ :openai-java-core:compileExternalApiCompatibilityKotlin \ :openai-java-core:compileProposedApiCompatibilityKotlin \ --no-build-cache + +validate_public_api_signatures() { + local manifest_path="$1" + local policy_name="$2" + local require_exact_match="$3" + local classes_root + local actual_signatures + local classes + local expected_signatures + local missing_signatures + local unexpected_signatures + local expected + local class_and_method + local descriptor + local class_name + local method_name + local extra + + classes_root="$(pwd)/openai-java-core/build/classes/kotlin/main" + actual_signatures="$(mktemp)" + classes="$(mktemp)" + expected_signatures="$(mktemp)" + missing_signatures="$(mktemp)" + unexpected_signatures="$(mktemp)" + + while IFS= read -r expected || [ -n "${expected}" ]; do + case "${expected}" in + ''|\#*) continue ;; + esac + + read -r class_and_method descriptor extra <<< "${expected}" + class_name="${class_and_method%#*}" + method_name="${class_and_method##*#}" + + if [ -n "${extra:-}" ] || + [[ ! "${class_name}" =~ ^[A-Za-z0-9_.\$]+$ ]] || + [[ ! "${method_name}" =~ ^[A-Za-z0-9_]+$ ]] || + [[ ! "${descriptor}" =~ ^\([^[:space:]]*\)[^[:space:]]+$ ]]; then + echo "Invalid ${policy_name} public API signature: ${expected}" >&2 + exit 1 + fi + + printf '%s\n' "${class_name}" >> "${classes}" + printf '%s\n' "${expected}" >> "${expected_signatures}" + done < "${manifest_path}" + + if [ ! -s "${classes}" ]; then + echo "No ${policy_name} public API classes found in ${manifest_path}" >&2 + exit 1 + fi + + LC_ALL=C sort -u "${classes}" -o "${classes}" + if [ "$(LC_ALL=C sort "${expected_signatures}" | uniq -d | wc -l)" -ne 0 ]; then + echo "${policy_name} public API manifest contains duplicate signatures" >&2 + LC_ALL=C sort "${expected_signatures}" | uniq -d >&2 + exit 1 + fi + LC_ALL=C sort -o "${expected_signatures}" "${expected_signatures}" + + while IFS= read -r class_name; do + if ! javap -classpath "${classes_root}" -public -s "${class_name}" | + awk -v class_name="${class_name}" ' + /^ public/ && /\(/ { + declaration = $0 + sub(/\(.*/, "", declaration) + count = split(declaration, fields, /[[:space:]]+/) + method_name = fields[count] + next + } + /descriptor:/ && method_name != "" { + if (method_name !~ /\$/ && method_name !~ /^com\.openai\./ && method_name != "equals" && method_name != "hashCode" && method_name != "toString") { + print class_name "#" method_name " " $2 + } + method_name = "" + } + ' >> "${actual_signatures}"; then + echo "${policy_name} public API class is missing: ${class_name}" >&2 + exit 1 + fi + done < "${classes}" + + LC_ALL=C sort -u -o "${actual_signatures}" "${actual_signatures}" + comm -23 "${expected_signatures}" "${actual_signatures}" > "${missing_signatures}" + if [ -s "${missing_signatures}" ]; then + echo "${policy_name} structured-output API is missing:" >&2 + sed 's/^/ /' "${missing_signatures}" >&2 + exit 1 + fi + + if [ "${require_exact_match}" = true ]; then + comm -13 "${expected_signatures}" "${actual_signatures}" > "${unexpected_signatures}" + if [ -s "${unexpected_signatures}" ]; then + echo "${policy_name} structured-output API manifest is incomplete:" >&2 + sed 's/^/ /' "${unexpected_signatures}" >&2 + exit 1 + fi + fi + + rm -f \ + "${actual_signatures}" \ + "${classes}" \ + "${expected_signatures}" \ + "${missing_signatures}" \ + "${unexpected_signatures}" + echo "${policy_name} structured-output public API is compatible." +} + +validate_public_api_signatures "${BASELINE_PUBLIC_API_PATH}" baseline false +validate_public_api_signatures "${PROPOSED_PUBLIC_API_PATH}" proposed true