From 9b778052e0e8fcf3084866aadd5a55ee918b1682 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:24:41 +0000 Subject: [PATCH 001/164] chore: configure new SDK language --- .devcontainer/Dockerfile | 23 + .devcontainer/devcontainer.json | 20 + .gitattributes | 5 + .github/workflows/ci.yml | 85 + .gitignore | 7 + .stats.yml | 4 + LICENSE | 201 +++ README.md | 636 ++++++- SECURITY.md | 23 + build.gradle.kts | 49 + buildSrc/build.gradle.kts | 12 + .../src/main/kotlin/stagehand.java.gradle.kts | 136 ++ .../main/kotlin/stagehand.kotlin.gradle.kts | 106 ++ .../main/kotlin/stagehand.publish.gradle.kts | 60 + gradle.properties | 18 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 7 + gradlew | 251 +++ gradlew.bat | 94 + scripts/build | 8 + scripts/fast-format | 46 + scripts/format | 21 + scripts/java-format | 7 + scripts/kotlin-format | 7 + scripts/lint | 23 + scripts/mock | 41 + scripts/test | 56 + settings.gradle.kts | 14 + stagehand-java-client-okhttp/build.gradle.kts | 15 + .../api/client/okhttp/OkHttpClient.kt | 252 +++ .../client/okhttp/StagehandOkHttpClient.kt | 316 ++++ .../okhttp/StagehandOkHttpClientAsync.kt | 316 ++++ .../api/client/okhttp/OkHttpClientTest.kt | 44 + stagehand-java-core/build.gradle.kts | 41 + .../stagehand/api/client/StagehandClient.kt | 72 + .../api/client/StagehandClientAsync.kt | 76 + .../api/client/StagehandClientAsyncImpl.kt | 59 + .../api/client/StagehandClientImpl.kt | 57 + .../stagehand/api/core/BaseDeserializer.kt | 44 + .../com/stagehand/api/core/BaseSerializer.kt | 6 + .../kotlin/com/stagehand/api/core/Check.kt | 96 + .../com/stagehand/api/core/ClientOptions.kt | 463 +++++ .../com/stagehand/api/core/DefaultSleeper.kt | 28 + .../com/stagehand/api/core/ObjectMappers.kt | 167 ++ .../kotlin/com/stagehand/api/core/Params.kt | 16 + .../stagehand/api/core/PhantomReachable.kt | 56 + .../core/PhantomReachableExecutorService.kt | 58 + .../api/core/PhantomReachableSleeper.kt | 23 + .../com/stagehand/api/core/PrepareRequest.kt | 24 + .../com/stagehand/api/core/Properties.kt | 42 + .../com/stagehand/api/core/RequestOptions.kt | 46 + .../kotlin/com/stagehand/api/core/Sleeper.kt | 21 + .../kotlin/com/stagehand/api/core/Timeout.kt | 171 ++ .../kotlin/com/stagehand/api/core/Utils.kt | 115 ++ .../kotlin/com/stagehand/api/core/Values.kt | 723 ++++++++ .../api/core/handlers/ErrorHandler.kt | 84 + .../api/core/handlers/JsonHandler.kt | 20 + .../api/core/handlers/StringHandler.kt | 13 + .../api/core/http/AsyncStreamResponse.kt | 157 ++ .../com/stagehand/api/core/http/Headers.kt | 115 ++ .../com/stagehand/api/core/http/HttpClient.kt | 26 + .../com/stagehand/api/core/http/HttpMethod.kt | 13 + .../stagehand/api/core/http/HttpRequest.kt | 146 ++ .../api/core/http/HttpRequestBodies.kt | 130 ++ .../api/core/http/HttpRequestBody.kt | 25 + .../stagehand/api/core/http/HttpResponse.kt | 22 + .../api/core/http/HttpResponseFor.kt | 25 + ...ntomReachableClosingAsyncStreamResponse.kt | 56 + .../http/PhantomReachableClosingHttpClient.kt | 26 + .../PhantomReachableClosingStreamResponse.kt | 21 + .../stagehand/api/core/http/QueryParams.kt | 129 ++ .../api/core/http/RetryingHttpClient.kt | 265 +++ .../stagehand/api/core/http/StreamResponse.kt | 19 + .../api/errors/BadRequestException.kt | 80 + .../api/errors/InternalServerException.kt | 91 + .../stagehand/api/errors/NotFoundException.kt | 76 + .../api/errors/PermissionDeniedException.kt | 80 + .../api/errors/RateLimitException.kt | 80 + .../api/errors/StagehandException.kt | 5 + .../errors/StagehandInvalidDataException.kt | 5 + .../api/errors/StagehandIoException.kt | 5 + .../api/errors/StagehandRetryableException.kt | 14 + .../api/errors/StagehandServiceException.kt | 17 + .../api/errors/UnauthorizedException.kt | 80 + .../errors/UnexpectedStatusCodeException.kt | 92 + .../errors/UnprocessableEntityException.kt | 80 + .../stagehand/api/models/sessions/Action.kt | 350 ++++ .../api/models/sessions/ModelConfig.kt | 392 +++++ .../api/models/sessions/SessionActParams.kt | 1233 +++++++++++++ .../api/models/sessions/SessionActResponse.kt | 269 +++ .../api/models/sessions/SessionEndParams.kt | 229 +++ .../api/models/sessions/SessionEndResponse.kt | 153 ++ .../sessions/SessionExecuteAgentParams.kt | 1547 +++++++++++++++++ .../sessions/SessionExecuteAgentResponse.kt | 212 +++ .../models/sessions/SessionExtractParams.kt | 1064 ++++++++++++ .../models/sessions/SessionExtractResponse.kt | 459 +++++ .../models/sessions/SessionNavigateParams.kt | 992 +++++++++++ .../sessions/SessionNavigateResponse.kt | 216 +++ .../models/sessions/SessionObserveParams.kt | 902 ++++++++++ .../api/models/sessions/SessionStartParams.kt | 1266 ++++++++++++++ .../models/sessions/SessionStartResponse.kt | 213 +++ .../api/services/async/SessionServiceAsync.kt | 479 +++++ .../services/async/SessionServiceAsyncImpl.kt | 347 ++++ .../api/services/blocking/SessionService.kt | 475 +++++ .../services/blocking/SessionServiceImpl.kt | 319 ++++ .../META-INF/proguard/stagehand-java-core.pro | 32 + .../com/stagehand/api/TestServerExtension.kt | 62 + .../stagehand/api/core/ClientOptionsTest.kt | 34 + .../stagehand/api/core/ObjectMappersTest.kt | 102 ++ .../api/core/PhantomReachableTest.kt | 27 + .../com/stagehand/api/core/UtilsTest.kt | 33 + .../com/stagehand/api/core/ValuesTest.kt | 144 ++ .../api/core/http/AsyncStreamResponseTest.kt | 268 +++ .../stagehand/api/core/http/HeadersTest.kt | 242 +++ .../api/core/http/QueryParamsTest.kt | 180 ++ .../api/core/http/RetryingHttpClientTest.kt | 356 ++++ .../api/models/sessions/ActionTest.kt | 47 + .../api/models/sessions/ModelConfigTest.kt | 47 + .../models/sessions/SessionActParamsTest.kt | 166 ++ .../models/sessions/SessionActResponseTest.kt | 69 + .../models/sessions/SessionEndParamsTest.kt | 24 + .../models/sessions/SessionEndResponseTest.kt | 32 + .../sessions/SessionExecuteAgentParamsTest.kt | 170 ++ .../SessionExecuteAgentResponseTest.kt | 44 + .../sessions/SessionExtractParamsTest.kt | 158 ++ .../sessions/SessionExtractResponseTest.kt | 94 + .../sessions/SessionNavigateParamsTest.kt | 111 ++ .../sessions/SessionNavigateResponseTest.kt | 36 + .../sessions/SessionObserveParamsTest.kt | 136 ++ .../models/sessions/SessionStartParamsTest.kt | 66 + .../sessions/SessionStartResponseTest.kt | 42 + .../api/services/ErrorHandlingTest.kt | 673 +++++++ .../api/services/ServiceParamsTest.kt | 71 + .../services/async/SessionServiceAsyncTest.kt | 262 +++ .../services/blocking/SessionServiceTest.kt | 255 +++ stagehand-java-example/build.gradle.kts | 28 + stagehand-java-lib/.keep | 4 + stagehand-java-proguard-test/build.gradle.kts | 101 ++ .../api/proguard/ProGuardCompatibilityTest.kt | 88 + stagehand-java-proguard-test/test.pro | 9 + stagehand-java/build.gradle.kts | 29 + 141 files changed, 22662 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .gitattributes create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .stats.yml create mode 100644 LICENSE create mode 100644 SECURITY.md create mode 100644 build.gradle.kts create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/stagehand.java.gradle.kts create mode 100644 buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts create mode 100644 buildSrc/src/main/kotlin/stagehand.publish.gradle.kts create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100755 scripts/build create mode 100755 scripts/fast-format create mode 100755 scripts/format create mode 100755 scripts/java-format create mode 100755 scripts/kotlin-format create mode 100755 scripts/lint create mode 100755 scripts/mock create mode 100755 scripts/test create mode 100644 settings.gradle.kts create mode 100644 stagehand-java-client-okhttp/build.gradle.kts create mode 100644 stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt create mode 100644 stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt create mode 100644 stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt create mode 100644 stagehand-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt create mode 100644 stagehand-java-core/build.gradle.kts create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt create mode 100644 stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt create mode 100644 stagehand-java-example/build.gradle.kts create mode 100644 stagehand-java-lib/.keep create mode 100644 stagehand-java-proguard-test/build.gradle.kts create mode 100644 stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt create mode 100644 stagehand-java-proguard-test/test.pro create mode 100644 stagehand-java/build.gradle.kts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..bd8e261 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,23 @@ +# syntax=docker/dockerfile:1 +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libxkbcommon0 \ + ca-certificates \ + ca-certificates-java \ + make \ + curl \ + git \ + openjdk-17-jdk-headless \ + unzip \ + libc++1 \ + vim \ + && apt-get clean autoclean + +# Ensure UTF-8 encoding +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +WORKDIR /workspace + +COPY . /workspace diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..d55fc4d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Debian", + "build": { + "dockerfile": "Dockerfile" + } + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..022b841 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7186ff6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,85 @@ +name: CI +on: + push: + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' + +jobs: + lint: + timeout-minutes: 15 + name: lint + runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 8 + 21 + cache: gradle + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Run lints + run: ./scripts/lint + + build: + timeout-minutes: 15 + name: build + runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 8 + 21 + cache: gradle + + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build SDK + run: ./scripts/build + + test: + timeout-minutes: 15 + name: test + runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 8 + 21 + cache: gradle + + - name: Set up Gradle + uses: gradle/gradle-build-action@v2 + + - name: Run tests + run: ./scripts/test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1346e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.prism.log +.gradle +.idea +.kotlin +build/ +codegen.log +kls_database.db diff --git a/.stats.yml b/.stats.yml new file mode 100644 index 0000000..b286614 --- /dev/null +++ b/.stats.yml @@ -0,0 +1,4 @@ +configured_endpoints: 7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml +openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 +config_hash: 56543e7140dd04c5cc539051f40f0689 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6b24314 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Stagehand + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index eaf1a54..02a29e4 100644 --- a/README.md +++ b/README.md @@ -1 +1,635 @@ -# stagehand-java \ No newline at end of file +# Stagehand Java API Library + +[![Maven Central](https://img.shields.io/maven-central/v/com.stagehand.api/stagehand-java)](https://central.sonatype.com/artifact/com.stagehand.api/stagehand-java/0.0.1) +[![javadoc](https://javadoc.io/badge2/com.stagehand.api/stagehand-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.stagehand.api/stagehand-java/0.0.1) + +The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://browserbase.com) from applications written in Java. + +It is generated with [Stainless](https://www.stainless.com/). + +The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.stagehand.api/stagehand-java/0.0.1). + +## Installation + +### Gradle + +```kotlin +implementation("com.stagehand.api:stagehand-java:0.0.1") +``` + +### Maven + +```xml + + com.stagehand.api + stagehand-java + 0.0.1 + +``` + +## Requirements + +This library requires Java 8 or later. + +## Usage + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.models.sessions.SessionStartParams; +import com.stagehand.api.models.sessions.SessionStartResponse; + +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.fromEnv(); + +SessionStartParams params = SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .build(); +SessionStartResponse response = client.sessions().start(params); +``` + +## Client configuration + +Configure the client using system properties or environment variables: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.fromEnv(); +``` + +Or manually: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +StagehandClient client = StagehandOkHttpClient.builder() + .apiKey("My API Key") + .build(); +``` + +Or using a combination of the two approaches: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +StagehandClient client = StagehandOkHttpClient.builder() + // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties + // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables + .fromEnv() + .apiKey("My API Key") + .build(); +``` + +See this table for the available options: + +| Setter | System property | Environment variable | Required | Default value | +| --------- | ------------------- | -------------------- | -------- | ---------------------------- | +| `apiKey` | `stagehand.apiKey` | `STAGEHAND_API_KEY` | false | - | +| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"http://localhost:3000/v1"` | + +System properties take precedence over environment variables. + +> [!TIP] +> Don't create more than one client in the same application. Each client has a connection pool and +> thread pools, which are more efficient to share between requests. + +### Modifying configuration + +To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service: + +```java +import com.stagehand.api.client.StagehandClient; + +StagehandClient clientWithOptions = client.withOptions(optionsBuilder -> { + optionsBuilder.baseUrl("https://example.com"); + optionsBuilder.maxRetries(42); +}); +``` + +The `withOptions()` method does not affect the original client or service. + +## Requests and responses + +To send a request to the Stagehand API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. + +For example, `client.sessions().start(...)` should be called with an instance of `SessionStartParams`, and it will return an instance of `SessionStartResponse`. + +## Immutability + +Each class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it. + +Each class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy. + +Because each class is immutable, builder modification will _never_ affect already built class instances. + +## Asynchronous execution + +The default client is synchronous. To switch to asynchronous execution, call the `async()` method: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.models.sessions.SessionStartParams; +import com.stagehand.api.models.sessions.SessionStartResponse; +import java.util.concurrent.CompletableFuture; + +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.fromEnv(); + +SessionStartParams params = SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .build(); +CompletableFuture response = client.async().sessions().start(params); +``` + +Or create an asynchronous client from the beginning: + +```java +import com.stagehand.api.client.StagehandClientAsync; +import com.stagehand.api.client.okhttp.StagehandOkHttpClientAsync; +import com.stagehand.api.models.sessions.SessionStartParams; +import com.stagehand.api.models.sessions.SessionStartResponse; +import java.util.concurrent.CompletableFuture; + +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); + +SessionStartParams params = SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .build(); +CompletableFuture response = client.sessions().start(params); +``` + +The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. + +## Raw responses + +The SDK defines methods that deserialize responses into instances of Java classes. However, these methods don't provide access to the response headers, status code, or the raw response body. + +To access this data, prefix any HTTP method call on a client or service with `withRawResponse()`: + +```java +import com.stagehand.api.core.http.Headers; +import com.stagehand.api.core.http.HttpResponseFor; +import com.stagehand.api.models.sessions.SessionStartParams; +import com.stagehand.api.models.sessions.SessionStartResponse; + +SessionStartParams params = SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .build(); +HttpResponseFor response = client.sessions().withRawResponse().start(params); + +int statusCode = response.statusCode(); +Headers headers = response.headers(); +``` + +You can still deserialize the response into an instance of a Java class if needed: + +```java +import com.stagehand.api.models.sessions.SessionStartResponse; + +SessionStartResponse parsedResponse = response.parse(); +``` + +## Error handling + +The SDK throws custom unchecked exception types: + +- [`StagehandServiceException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: + + | Status | Exception | + | ------ | -------------------------------------------------------------------------------------------------------------------------------- | + | 400 | [`BadRequestException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt) | + | 401 | [`UnauthorizedException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt) | + | 403 | [`PermissionDeniedException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt) | + | 404 | [`NotFoundException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt) | + | 422 | [`UnprocessableEntityException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt) | + | 429 | [`RateLimitException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt) | + | 5xx | [`InternalServerException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt) | + | others | [`UnexpectedStatusCodeException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt) | + +- [`StagehandIoException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt): I/O networking errors. + +- [`StagehandRetryableException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt): Generic error indicating a failure that could be retried by the client. + +- [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. + +- [`StagehandException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. + +## Logging + +The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). + +Enable logging by setting the `STAGEHAND_LOG` environment variable to `info`: + +```sh +export STAGEHAND_LOG=info +``` + +Or to `debug` for more verbose logging: + +```sh +export STAGEHAND_LOG=debug +``` + +## ProGuard and R8 + +Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `stagehand-java-core` is published with a [configuration file](stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). + +ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary. + +## Jackson + +The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default. + +The SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config). + +If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt). + +> [!CAUTION] +> We make no guarantee that the SDK works correctly when the Jackson version check is disabled. + +## Network options + +### Retries + +The SDK automatically retries 2 times by default, with a short exponential backoff between requests. + +Only the following error types are retried: + +- Connection errors (for example, due to a network connectivity problem) +- 408 Request Timeout +- 409 Conflict +- 429 Rate Limit +- 5xx Internal + +The API may also explicitly instruct the SDK to retry or not retry a request. + +To set a custom number of retries, configure the client using the `maxRetries` method: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .maxRetries(4) + .build(); +``` + +### Timeouts + +Requests time out after 1 minute by default. + +To set a custom timeout, configure the method call using the `timeout` method: + +```java +import com.stagehand.api.models.sessions.SessionStartResponse; + +SessionStartResponse response = client.sessions().start( + params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() +); +``` + +Or configure the default for all method calls at the client level: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import java.time.Duration; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .timeout(Duration.ofSeconds(30)) + .build(); +``` + +### Proxies + +To route requests through a proxy, configure the client using the `proxy` method: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import java.net.InetSocketAddress; +import java.net.Proxy; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .proxy(new Proxy( + Proxy.Type.HTTP, new InetSocketAddress( + "https://example.com", 8080 + ) + )) + .build(); +``` + +### HTTPS + +> [!NOTE] +> Most applications should not call these methods, and instead use the system defaults. The defaults include +> special optimizations that can be lost if the implementations are modified. + +To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa. + .sslSocketFactory(yourSSLSocketFactory) + .trustManager(yourTrustManager) + .hostnameVerifier(yourHostnameVerifier) + .build(); +``` + +### Environments + +The SDK sends requests to the production by default. To send requests to a different environment, configure the client like so: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .environment1() + .build(); +``` + +### Custom HTTP client + +The SDK consists of three artifacts: + +- `stagehand-java-core` + - Contains core SDK logic + - Does not depend on [OkHttp](https://square.github.io/okhttp) + - Exposes [`StagehandClient`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt), [`StagehandClientAsync`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt), [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt), and [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), all of which can work with any HTTP client +- `stagehand-java-client-okhttp` + - Depends on [OkHttp](https://square.github.io/okhttp) + - Exposes [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) and [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt), which provide a way to construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt) and [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), respectively, using OkHttp +- `stagehand-java` + - Depends on and exposes the APIs of both `stagehand-java-core` and `stagehand-java-client-okhttp` + - Does not have its own logic + +This structure allows replacing the SDK's default HTTP client without pulling in unnecessary dependencies. + +#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html) + +> [!TIP] +> Try the available [network options](#network-options) before replacing the default client. + +To use a customized `OkHttpClient`: + +1. Replace your [`stagehand-java` dependency](#installation) with `stagehand-java-core` +2. Copy `stagehand-java-client-okhttp`'s [`OkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt) class into your code and customize it +3. Construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt) or [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), similarly to [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt), using your customized client + +### Completely custom HTTP client + +To use a completely custom HTTP client: + +1. Replace your [`stagehand-java` dependency](#installation) with `stagehand-java-core` +2. Write a class that implements the [`HttpClient`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt) interface +3. Construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt) or [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), similarly to [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt), using your new client class + +## Undocumented API functionality + +The SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API. + +### Parameters + +To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class: + +```java +import com.stagehand.api.core.JsonValue; +import com.stagehand.api.models.sessions.SessionStartParams; + +SessionStartParams params = SessionStartParams.builder() + .putAdditionalHeader("Secret-Header", "42") + .putAdditionalQueryParam("secret_query_param", "42") + .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) + .build(); +``` + +These can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods. + +To set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class: + +```java +import com.stagehand.api.core.JsonValue; +import com.stagehand.api.models.sessions.SessionStartParams; + +SessionStartParams params = SessionStartParams.builder() + .localBrowserLaunchOptions(SessionStartParams.LocalBrowserLaunchOptions.builder() + .putAdditionalProperty("secretProperty", JsonValue.from("42")) + .build()) + .build(); +``` + +These properties can be accessed on the nested built object later using the `_additionalProperties()` method. + +To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) object to its setter: + +```java +import com.stagehand.api.core.JsonValue; +import com.stagehand.api.models.sessions.SessionStartParams; + +SessionStartParams params = SessionStartParams.builder() + .env(JsonValue.from(42)) + .build(); +``` + +The most straightforward way to create a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) is using its `from(...)` method: + +```java +import com.stagehand.api.core.JsonValue; +import java.util.List; +import java.util.Map; + +// Create primitive JSON values +JsonValue nullValue = JsonValue.from(null); +JsonValue booleanValue = JsonValue.from(true); +JsonValue numberValue = JsonValue.from(42); +JsonValue stringValue = JsonValue.from("Hello World!"); + +// Create a JSON array value equivalent to `["Hello", "World"]` +JsonValue arrayValue = JsonValue.from(List.of( + "Hello", "World" +)); + +// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }` +JsonValue objectValue = JsonValue.from(Map.of( + "a", 1, + "b", 2 +)); + +// Create an arbitrarily nested JSON equivalent to: +// { +// "a": [1, 2], +// "b": [3, 4] +// } +JsonValue complexValue = JsonValue.from(Map.of( + "a", List.of( + 1, 2 + ), + "b", List.of( + 3, 4 + ) +)); +``` + +Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. + +To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt): + +```java +import com.stagehand.api.core.JsonMissing; +import com.stagehand.api.models.sessions.SessionStartParams; + +SessionStartParams params = SessionStartParams.builder() + .env(JsonMissing.of()) + .build(); +``` + +### Response properties + +To access undocumented response properties, call the `_additionalProperties()` method: + +```java +import com.stagehand.api.core.JsonValue; +import java.util.Map; + +Map additionalProperties = client.sessions().start(params)._additionalProperties(); +JsonValue secretPropertyValue = additionalProperties.get("secretProperty"); + +String result = secretPropertyValue.accept(new JsonValue.Visitor<>() { + @Override + public String visitNull() { + return "It's null!"; + } + + @Override + public String visitBoolean(boolean value) { + return "It's a boolean!"; + } + + @Override + public String visitNumber(Number value) { + return "It's a number!"; + } + + // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject` + // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden +}); +``` + +To access a property's raw JSON value, which may be undocumented, call its `_` prefixed method: + +```java +import com.stagehand.api.core.JsonField; +import com.stagehand.api.models.sessions.SessionStartParams; +import java.util.Optional; + +JsonField env = client.sessions().start(params)._env(); + +if (env.isMissing()) { + // The property is absent from the JSON response +} else if (env.isNull()) { + // The property was set to literal null +} else { + // Check if value was provided as a string + // Other methods include `asNumber()`, `asBoolean()`, etc. + Optional jsonString = env.asString(); + + // Try to deserialize into a custom type + MyClass myObject = env.asUnknown().orElseThrow().convert(MyClass.class); +} +``` + +### Response validation + +In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else. + +By default, the SDK will not throw an exception in this case. It will throw [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt) only if you directly access the property. + +If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: + +```java +import com.stagehand.api.models.sessions.SessionStartResponse; + +SessionStartResponse response = client.sessions().start(params).validate(); +``` + +Or configure the method call to validate the response using the `responseValidation` method: + +```java +import com.stagehand.api.models.sessions.SessionStartResponse; + +SessionStartResponse response = client.sessions().start( + params, RequestOptions.builder().responseValidation(true).build() +); +``` + +Or configure the default for all method calls at the client level: + +```java +import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.okhttp.StagehandOkHttpClient; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .responseValidation(true) + .build(); +``` + +## FAQ + +### Why don't you use plain `enum` classes? + +Java `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value. + +### Why do you represent fields using `JsonField` instead of just plain `T`? + +Using `JsonField` enables a few features: + +- Allowing usage of [undocumented API functionality](#undocumented-api-functionality) +- Lazily [validating the API response against the expected shape](#response-validation) +- Representing absent vs explicitly null values + +### Why don't you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)? + +It is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don't want to introduce a breaking change every time we add a field to a class. + +### Why don't you use checked exceptions? + +Checked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason. + +Checked exceptions: + +- Are verbose to handle +- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error +- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function) +- Don't play well with lambdas (also due to the function coloring problem) + +## Semantic versioning + +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: + +1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ +2. Changes that we do not expect to impact the vast majority of users in practice. + +We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. + +We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/stagehand-java/issues) with questions, bugs, or suggestions. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..dcfc419 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainless.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Stagehand, please follow the respective company's security reporting guidelines. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..cca6e8a --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,49 @@ +plugins { + id("io.github.gradle-nexus.publish-plugin") version "1.1.0" + id("org.jetbrains.dokka") version "2.0.0" +} + +repositories { + mavenCentral() +} + +allprojects { + group = "com.stagehand.api" + version = "0.0.1" +} + +subprojects { + // These are populated with dependencies by `buildSrc` scripts. + tasks.register("format") { + group = "Verification" + description = "Formats all source files." + } + tasks.register("lint") { + group = "Verification" + description = "Verifies all source files are formatted." + } + apply(plugin = "org.jetbrains.dokka") +} + +subprojects { + apply(plugin = "org.jetbrains.dokka") +} + +// Avoid race conditions between `dokkaJavadocCollector` and `dokkaJavadocJar` tasks +tasks.named("dokkaJavadocCollector").configure { + subprojects.flatMap { it.tasks } + .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } + .forEach { mustRunAfter(it) } +} + +nexusPublishing { + repositories { + sonatype { + nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) + snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) + + username.set(System.getenv("SONATYPE_USERNAME")) + password.set(System.getenv("SONATYPE_PASSWORD")) + } + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..0b14135 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + `kotlin-dsl` + kotlin("jvm") version "1.9.20" +} + +repositories { + gradlePluginPortal() +} + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") +} diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts new file mode 100644 index 0000000..81d5d32 --- /dev/null +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -0,0 +1,136 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat + +plugins { + `java-library` +} + +repositories { + mavenCentral() +} + +configure { + withJavadocJar() + withSourcesJar() +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType().configureEach { + options.compilerArgs.add("-Werror") + options.release.set(8) +} + +tasks.named("javadocJar") { + setZip64(true) +} + +tasks.named("jar") { + manifest { + attributes(mapOf( + "Implementation-Title" to project.name, + "Implementation-Version" to project.version + )) + } +} + +tasks.withType().configureEach { + useJUnitPlatform() + + // Run tests in parallel to some degree. + maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(1) + forkEvery = 100 + + testLogging { + exceptionFormat = TestExceptionFormat.FULL + } +} + +val palantir by configurations.creating +dependencies { + palantir("com.palantir.javaformat:palantir-java-format:2.73.0") +} + +fun registerPalantir( + name: String, + description: String, +) { + val javaName = "${name}Java" + tasks.register(javaName) { + group = "Verification" + this.description = description + + classpath = palantir + mainClass = "com.palantir.javaformat.java.Main" + + // Avoid an `IllegalAccessError` on Java 9+. + jvmArgs( + "--add-exports", "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "--add-exports", "jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", + "--add-exports", "jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", + "--add-exports", "jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "--add-exports", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + ) + + // Use paths relative to the current module. + val argumentFile = + project.layout.buildDirectory.file("palantir-$name-args.txt").get().asFile + val lastRunTimeFile = + project.layout.buildDirectory.file("palantir-$name-last-run.txt").get().asFile + + // Read the time when this task was last executed for this module (if ever). + val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L + + // Use a `fileTree` relative to the module's source directory. + val javaFiles = project.fileTree("src") { include("**/*.java") } + + // Determine if any files need to be formatted or linted and continue only if there is at least + // one file. + onlyIf { javaFiles.any { it.lastModified() > lastRunTime } } + + inputs.files(javaFiles) + + doFirst { + // Create the argument file and set the preferred formatting style. + argumentFile.parentFile.mkdirs() + argumentFile.writeText("--palantir\n") + + if (name == "lint") { + // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of + // the default 0) if any files need to be formatted, indicating that linting has failed. + argumentFile.appendText("--dry-run\n") + argumentFile.appendText("--set-exit-if-changed\n") + } else { + // `--dry-run` and `--replace` (for in-place formatting) are mutually exclusive. + argumentFile.appendText("--replace\n") + } + + // Write the modified files to the argument file. + javaFiles.filter { it.lastModified() > lastRunTime } + .forEach { argumentFile.appendText("${it.absolutePath}\n") } + } + + doLast { + // Record the last execution time for later up-to-date checking. + lastRunTimeFile.writeText(System.currentTimeMillis().toString()) + } + + // Pass the argument file using the @ symbol + args = listOf("@${argumentFile.absolutePath}") + + outputs.upToDateWhen { javaFiles.none { it.lastModified() > lastRunTime } } + } + + tasks.named(name) { + dependsOn(tasks.named(javaName)) + } +} + +registerPalantir(name = "format", description = "Formats all Java source files.") +registerPalantir(name = "lint", description = "Verifies all Java source files are formatted.") diff --git a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts new file mode 100644 index 0000000..f3f48d1 --- /dev/null +++ b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts @@ -0,0 +1,106 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion + +plugins { + id("stagehand.java") + kotlin("jvm") +} + +repositories { + mavenCentral() +} + +kotlin { + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + + compilerOptions { + freeCompilerArgs = listOf( + "-Xjvm-default=all", + "-Xjdk-release=1.8", + // Suppress deprecation warnings because we may still reference and test deprecated members. + // TODO: Replace with `-Xsuppress-warning=DEPRECATION` once we use Kotlin compiler 2.1.0+. + "-nowarn", + ) + jvmTarget.set(JvmTarget.JVM_1_8) + languageVersion.set(KotlinVersion.KOTLIN_1_8) + apiVersion.set(KotlinVersion.KOTLIN_1_8) + coreLibrariesVersion = "1.8.0" + } +} + +tasks.withType().configureEach { + systemProperty("junit.jupiter.execution.parallel.enabled", true) + systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") +} + +val ktfmt by configurations.creating +dependencies { + ktfmt("com.facebook:ktfmt:0.56") +} + +fun registerKtfmt( + name: String, + description: String, +) { + val kotlinName = "${name}Kotlin" + tasks.register(kotlinName) { + group = "Verification" + this.description = description + + classpath = ktfmt + mainClass = "com.facebook.ktfmt.cli.Main" + + // Use paths relative to the current module. + val argumentFile = project.layout.buildDirectory.file("ktfmt-$name-args.txt").get().asFile + val lastRunTimeFile = + project.layout.buildDirectory.file("ktfmt-$name-last-run.txt").get().asFile + + // Read the time when this task was last executed for this module (if ever). + val lastRunTime = lastRunTimeFile.takeIf { it.exists() }?.readText()?.toLongOrNull() ?: 0L + + // Use a `fileTree` relative to the module's source directory. + val kotlinFiles = project.fileTree("src") { include("**/*.kt") } + + // Determine if any files need to be formatted or linted and continue only if there is at least + // one file (otherwise Ktfmt will fail). + onlyIf { kotlinFiles.any { it.lastModified() > lastRunTime } } + + inputs.files(kotlinFiles) + + doFirst { + // Create the argument file and set the preferred formatting style. + argumentFile.parentFile.mkdirs() + argumentFile.writeText("--kotlinlang-style\n") + + if (name == "lint") { + // For lint, do a dry run, so no files are modified. Set the exit code to 1 (instead of + // the default 0) if any files need to be formatted, indicating that linting has failed. + argumentFile.appendText("--dry-run\n") + argumentFile.appendText("--set-exit-if-changed\n") + } + + // Write the modified files to the argument file. + kotlinFiles.filter { it.lastModified() > lastRunTime } + .forEach { argumentFile.appendText("${it.absolutePath}\n") } + } + + doLast { + // Record the last execution time for later up-to-date checking. + lastRunTimeFile.writeText(System.currentTimeMillis().toString()) + } + + // Pass the argument file using the @ symbol + args = listOf("@${argumentFile.absolutePath}") + + outputs.upToDateWhen { kotlinFiles.none { it.lastModified() > lastRunTime } } + } + + tasks.named(name) { + dependsOn(tasks.named(kotlinName)) + } +} + +registerKtfmt(name = "format", description = "Formats all Kotlin source files.") +registerKtfmt(name = "lint", description = "Verifies all Kotlin source files are formatted.") diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts new file mode 100644 index 0000000..df771cd --- /dev/null +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -0,0 +1,60 @@ +plugins { + `maven-publish` + signing +} + +configure { + publications { + register("maven") { + from(components["java"]) + + pom { + name.set("Stagehand P2P Server API") + description.set("HTTP API for remote Stagehand browser automation. This API allows clients to\nconnect to a Stagehand server and execute browser automation tasks remotely.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.") + url.set("https://browserbase.com") + + licenses { + license { + name.set("Apache-2.0") + } + } + + developers { + developer { + name.set("Stagehand") + } + } + + scm { + connection.set("scm:git:git://github.com/stainless-sdks/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/stainless-sdks/stagehand-java.git") + url.set("https://github.com/stainless-sdks/stagehand-java") + } + + versionMapping { + allVariants { + fromResolutionResult() + } + } + } + } + } +} + +signing { + val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null } + val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null } + val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null } + if (signingKey != null && signingPassword != null) { + useInMemoryPgpKeys( + signingKeyId, + signingKey, + signingPassword, + ) + sign(publishing.publications["maven"]) + } +} + +tasks.named("publish") { + dependsOn(":closeAndReleaseSonatypeStagingRepository") +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..6680f9c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +org.gradle.caching=true +org.gradle.configuration-cache=true +org.gradle.parallel=true +org.gradle.daemon=false +# These options improve our compilation and test performance. They are inherited by the Kotlin daemon. +org.gradle.jvmargs=\ + -Xms2g \ + -Xmx8g \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=256m \ + -XX:ReservedCodeCacheSize=1G \ + -XX:MetaspaceSize=512m \ + -XX:MaxMetaspaceSize=2G \ + -XX:TieredStopAtLevel=1 \ + -XX:GCTimeRatio=4 \ + -XX:CICompilerCount=4 \ + -XX:+OptimizeStringConcat \ + -XX:+UseStringDeduplication diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 zcma&N1CXTcmMvW9vTb(Rwr$&4wr$(C?dmSu>@vG-+vuvg^_??!{yS%8zW-#zn-LkA z5&1^$^{lnmUON?}LBF8_K|(?T0Ra(xUH{($5eN!MR#ZihR#HxkUPe+_R8Cn`RRs(P z_^*#_XlXmGv7!4;*Y%p4nw?{bNp@UZHv1?Um8r6)Fei3p@ClJn0ECfg1hkeuUU@Or zDaPa;U3fE=3L}DooL;8f;P0ipPt0Z~9P0)lbStMS)ag54=uL9ia-Lm3nh|@(Y?B`; zx_#arJIpXH!U{fbCbI^17}6Ri*H<>OLR%c|^mh8+)*h~K8Z!9)DPf zR2h?lbDZQ`p9P;&DQ4F0sur@TMa!Y}S8irn(%d-gi0*WxxCSk*A?3lGh=gcYN?FGl z7D=Js!i~0=u3rox^eO3i@$0=n{K1lPNU zwmfjRVmLOCRfe=seV&P*1Iq=^i`502keY8Uy-WNPwVNNtJFx?IwAyRPZo2Wo1+S(xF37LJZ~%i)kpFQ3Fw=mXfd@>%+)RpYQLnr}B~~zoof(JVm^^&f zxKV^+3D3$A1G;qh4gPVjhrC8e(VYUHv#dy^)(RoUFM?o%W-EHxufuWf(l*@-l+7vt z=l`qmR56K~F|v<^Pd*p~1_y^P0P^aPC##d8+HqX4IR1gu+7w#~TBFphJxF)T$2WEa zxa?H&6=Qe7d(#tha?_1uQys2KtHQ{)Qco)qwGjrdNL7thd^G5i8Os)CHqc>iOidS} z%nFEDdm=GXBw=yXe1W-ShHHFb?Cc70+$W~z_+}nAoHFYI1MV1wZegw*0y^tC*s%3h zhD3tN8b=Gv&rj}!SUM6|ajSPp*58KR7MPpI{oAJCtY~JECm)*m_x>AZEu>DFgUcby z1Qaw8lU4jZpQ_$;*7RME+gq1KySGG#Wql>aL~k9tLrSO()LWn*q&YxHEuzmwd1?aAtI zBJ>P=&$=l1efe1CDU;`Fd+_;&wI07?V0aAIgc(!{a z0Jg6Y=inXc3^n!U0Atk`iCFIQooHqcWhO(qrieUOW8X(x?(RD}iYDLMjSwffH2~tB z)oDgNBLB^AJBM1M^c5HdRx6fBfka`(LD-qrlh5jqH~);#nw|iyp)()xVYak3;Ybik z0j`(+69aK*B>)e_p%=wu8XC&9e{AO4c~O1U`5X9}?0mrd*m$_EUek{R?DNSh(=br# z#Q61gBzEpmy`$pA*6!87 zSDD+=@fTY7<4A?GLqpA?Pb2z$pbCc4B4zL{BeZ?F-8`s$?>*lXXtn*NC61>|*w7J* z$?!iB{6R-0=KFmyp1nnEmLsA-H0a6l+1uaH^g%c(p{iT&YFrbQ$&PRb8Up#X3@Zsk zD^^&LK~111%cqlP%!_gFNa^dTYT?rhkGl}5=fL{a`UViaXWI$k-UcHJwmaH1s=S$4 z%4)PdWJX;hh5UoK?6aWoyLxX&NhNRqKam7tcOkLh{%j3K^4Mgx1@i|Pi&}<^5>hs5 zm8?uOS>%)NzT(%PjVPGa?X%`N2TQCKbeH2l;cTnHiHppPSJ<7y-yEIiC!P*ikl&!B z%+?>VttCOQM@ShFguHVjxX^?mHX^hSaO_;pnyh^v9EumqSZTi+#f&_Vaija0Q-e*| z7ulQj6Fs*bbmsWp{`auM04gGwsYYdNNZcg|ph0OgD>7O}Asn7^Z=eI>`$2*v78;sj-}oMoEj&@)9+ycEOo92xSyY344^ z11Hb8^kdOvbf^GNAK++bYioknrpdN>+u8R?JxG=!2Kd9r=YWCOJYXYuM0cOq^FhEd zBg2puKy__7VT3-r*dG4c62Wgxi52EMCQ`bKgf*#*ou(D4-ZN$+mg&7$u!! z-^+Z%;-3IDwqZ|K=ah85OLwkO zKxNBh+4QHh)u9D?MFtpbl)us}9+V!D%w9jfAMYEb>%$A;u)rrI zuBudh;5PN}_6J_}l55P3l_)&RMlH{m!)ai-i$g)&*M`eN$XQMw{v^r@-125^RRCF0 z^2>|DxhQw(mtNEI2Kj(;KblC7x=JlK$@78`O~>V!`|1Lm-^JR$-5pUANAnb(5}B}JGjBsliK4& zk6y(;$e&h)lh2)L=bvZKbvh@>vLlreBdH8No2>$#%_Wp1U0N7Ank!6$dFSi#xzh|( zRi{Uw%-4W!{IXZ)fWx@XX6;&(m_F%c6~X8hx=BN1&q}*( zoaNjWabE{oUPb!Bt$eyd#$5j9rItB-h*5JiNi(v^e|XKAj*8(k<5-2$&ZBR5fF|JA z9&m4fbzNQnAU}r8ab>fFV%J0z5awe#UZ|bz?Ur)U9bCIKWEzi2%A+5CLqh?}K4JHi z4vtM;+uPsVz{Lfr;78W78gC;z*yTch~4YkLr&m-7%-xc ztw6Mh2d>_iO*$Rd8(-Cr1_V8EO1f*^@wRoSozS) zy1UoC@pruAaC8Z_7~_w4Q6n*&B0AjOmMWa;sIav&gu z|J5&|{=a@vR!~k-OjKEgPFCzcJ>#A1uL&7xTDn;{XBdeM}V=l3B8fE1--DHjSaxoSjNKEM9|U9#m2<3>n{Iuo`r3UZp;>GkT2YBNAh|b z^jTq-hJp(ebZh#Lk8hVBP%qXwv-@vbvoREX$TqRGTgEi$%_F9tZES@z8Bx}$#5eeG zk^UsLBH{bc2VBW)*EdS({yw=?qmevwi?BL6*=12k9zM5gJv1>y#ML4!)iiPzVaH9% zgSImetD@dam~e>{LvVh!phhzpW+iFvWpGT#CVE5TQ40n%F|p(sP5mXxna+Ev7PDwA zamaV4m*^~*xV+&p;W749xhb_X=$|LD;FHuB&JL5?*Y2-oIT(wYY2;73<^#46S~Gx| z^cez%V7x$81}UWqS13Gz80379Rj;6~WdiXWOSsdmzY39L;Hg3MH43o*y8ibNBBH`(av4|u;YPq%{R;IuYow<+GEsf@R?=@tT@!}?#>zIIn0CoyV!hq3mw zHj>OOjfJM3F{RG#6ujzo?y32m^tgSXf@v=J$ELdJ+=5j|=F-~hP$G&}tDZsZE?5rX ztGj`!S>)CFmdkccxM9eGIcGnS2AfK#gXwj%esuIBNJQP1WV~b~+D7PJTmWGTSDrR` zEAu4B8l>NPuhsk5a`rReSya2nfV1EK01+G!x8aBdTs3Io$u5!6n6KX%uv@DxAp3F@{4UYg4SWJtQ-W~0MDb|j-$lwVn znAm*Pl!?Ps&3wO=R115RWKb*JKoexo*)uhhHBncEDMSVa_PyA>k{Zm2(wMQ(5NM3# z)jkza|GoWEQo4^s*wE(gHz?Xsg4`}HUAcs42cM1-qq_=+=!Gk^y710j=66(cSWqUe zklbm8+zB_syQv5A2rj!Vbw8;|$@C!vfNmNV!yJIWDQ>{+2x zKjuFX`~~HKG~^6h5FntRpnnHt=D&rq0>IJ9#F0eM)Y-)GpRjiN7gkA8wvnG#K=q{q z9dBn8_~wm4J<3J_vl|9H{7q6u2A!cW{bp#r*-f{gOV^e=8S{nc1DxMHFwuM$;aVI^ zz6A*}m8N-&x8;aunp1w7_vtB*pa+OYBw=TMc6QK=mbA-|Cf* zvyh8D4LRJImooUaSb7t*fVfih<97Gf@VE0|z>NcBwBQze);Rh!k3K_sfunToZY;f2 z^HmC4KjHRVg+eKYj;PRN^|E0>Gj_zagfRbrki68I^#~6-HaHg3BUW%+clM1xQEdPYt_g<2K+z!$>*$9nQ>; zf9Bei{?zY^-e{q_*|W#2rJG`2fy@{%6u0i_VEWTq$*(ZN37|8lFFFt)nCG({r!q#9 z5VK_kkSJ3?zOH)OezMT{!YkCuSSn!K#-Rhl$uUM(bq*jY? zi1xbMVthJ`E>d>(f3)~fozjg^@eheMF6<)I`oeJYx4*+M&%c9VArn(OM-wp%M<-`x z7sLP1&3^%Nld9Dhm@$3f2}87!quhI@nwd@3~fZl_3LYW-B?Ia>ui`ELg z&Qfe!7m6ze=mZ`Ia9$z|ARSw|IdMpooY4YiPN8K z4B(ts3p%2i(Td=tgEHX z0UQ_>URBtG+-?0E;E7Ld^dyZ;jjw0}XZ(}-QzC6+NN=40oDb2^v!L1g9xRvE#@IBR zO!b-2N7wVfLV;mhEaXQ9XAU+>=XVA6f&T4Z-@AX!leJ8obP^P^wP0aICND?~w&NykJ#54x3_@r7IDMdRNy4Hh;h*!u(Ol(#0bJdwEo$5437-UBjQ+j=Ic>Q2z` zJNDf0yO6@mr6y1#n3)s(W|$iE_i8r@Gd@!DWDqZ7J&~gAm1#~maIGJ1sls^gxL9LLG_NhU!pTGty!TbhzQnu)I*S^54U6Yu%ZeCg`R>Q zhBv$n5j0v%O_j{QYWG!R9W?5_b&67KB$t}&e2LdMvd(PxN6Ir!H4>PNlerpBL>Zvyy!yw z-SOo8caEpDt(}|gKPBd$qND5#a5nju^O>V&;f890?yEOfkSG^HQVmEbM3Ugzu+UtH zC(INPDdraBN?P%kE;*Ae%Wto&sgw(crfZ#Qy(<4nk;S|hD3j{IQRI6Yq|f^basLY; z-HB&Je%Gg}Jt@={_C{L$!RM;$$|iD6vu#3w?v?*;&()uB|I-XqEKqZPS!reW9JkLewLb!70T7n`i!gNtb1%vN- zySZj{8-1>6E%H&=V}LM#xmt`J3XQoaD|@XygXjdZ1+P77-=;=eYpoEQ01B@L*a(uW zrZeZz?HJsw_4g0vhUgkg@VF8<-X$B8pOqCuWAl28uB|@r`19DTUQQsb^pfqB6QtiT z*`_UZ`fT}vtUY#%sq2{rchyfu*pCg;uec2$-$N_xgjZcoumE5vSI{+s@iLWoz^Mf; zuI8kDP{!XY6OP~q5}%1&L}CtfH^N<3o4L@J@zg1-mt{9L`s^z$Vgb|mr{@WiwAqKg zp#t-lhrU>F8o0s1q_9y`gQNf~Vb!F%70f}$>i7o4ho$`uciNf=xgJ>&!gSt0g;M>*x4-`U)ysFW&Vs^Vk6m%?iuWU+o&m(2Jm26Y(3%TL; zA7T)BP{WS!&xmxNw%J=$MPfn(9*^*TV;$JwRy8Zl*yUZi8jWYF>==j~&S|Xinsb%c z2?B+kpet*muEW7@AzjBA^wAJBY8i|#C{WtO_or&Nj2{=6JTTX05}|H>N2B|Wf!*3_ z7hW*j6p3TvpghEc6-wufFiY!%-GvOx*bZrhZu+7?iSrZL5q9}igiF^*R3%DE4aCHZ zqu>xS8LkW+Auv%z-<1Xs92u23R$nk@Pk}MU5!gT|c7vGlEA%G^2th&Q*zfg%-D^=f z&J_}jskj|Q;73NP4<4k*Y%pXPU2Thoqr+5uH1yEYM|VtBPW6lXaetokD0u z9qVek6Q&wk)tFbQ8(^HGf3Wp16gKmr>G;#G(HRBx?F`9AIRboK+;OfHaLJ(P>IP0w zyTbTkx_THEOs%Q&aPrxbZrJlio+hCC_HK<4%f3ZoSAyG7Dn`=X=&h@m*|UYO-4Hq0 z-Bq&+Ie!S##4A6OGoC~>ZW`Y5J)*ouaFl_e9GA*VSL!O_@xGiBw!AF}1{tB)z(w%c zS1Hmrb9OC8>0a_$BzeiN?rkPLc9%&;1CZW*4}CDDNr2gcl_3z+WC15&H1Zc2{o~i) z)LLW=WQ{?ricmC`G1GfJ0Yp4Dy~Ba;j6ZV4r{8xRs`13{dD!xXmr^Aga|C=iSmor% z8hi|pTXH)5Yf&v~exp3o+sY4B^^b*eYkkCYl*T{*=-0HniSA_1F53eCb{x~1k3*`W zr~};p1A`k{1DV9=UPnLDgz{aJH=-LQo<5%+Em!DNN252xwIf*wF_zS^!(XSm(9eoj z=*dXG&n0>)_)N5oc6v!>-bd(2ragD8O=M|wGW z!xJQS<)u70m&6OmrF0WSsr@I%T*c#Qo#Ha4d3COcX+9}hM5!7JIGF>7<~C(Ear^Sn zm^ZFkV6~Ula6+8S?oOROOA6$C&q&dp`>oR-2Ym3(HT@O7Sd5c~+kjrmM)YmgPH*tL zX+znN>`tv;5eOfX?h{AuX^LK~V#gPCu=)Tigtq9&?7Xh$qN|%A$?V*v=&-2F$zTUv z`C#WyIrChS5|Kgm_GeudCFf;)!WH7FI60j^0o#65o6`w*S7R@)88n$1nrgU(oU0M9 zx+EuMkC>(4j1;m6NoGqEkpJYJ?vc|B zOlwT3t&UgL!pX_P*6g36`ZXQ; z9~Cv}ANFnJGp(;ZhS(@FT;3e)0)Kp;h^x;$*xZn*k0U6-&FwI=uOGaODdrsp-!K$Ac32^c{+FhI-HkYd5v=`PGsg%6I`4d9Jy)uW0y%) zm&j^9WBAp*P8#kGJUhB!L?a%h$hJgQrx!6KCB_TRo%9{t0J7KW8!o1B!NC)VGLM5! zpZy5Jc{`r{1e(jd%jsG7k%I+m#CGS*BPA65ZVW~fLYw0dA-H_}O zrkGFL&P1PG9p2(%QiEWm6x;U-U&I#;Em$nx-_I^wtgw3xUPVVu zqSuKnx&dIT-XT+T10p;yjo1Y)z(x1fb8Dzfn8e yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)Hlo1euqTyM>^!HK*!Q2P;4UYrysje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT@ZzrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVuxbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<Ozh@Kw)#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Qnd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OIC;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+HGi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGwgH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&eP z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqAOQqLc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSche7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2zJ?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuOk559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&dRcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs26>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P{{s@sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9KnY#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7GbvoG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RHmw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)YsbHSz8!mG)WiJE| z2f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7yq$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`ltNebF46ZX_BbZNU}}ZOm{M2&nANL9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`(M!j~B;#x?Ba~&s6CopvO86oM?-? zOw#dIRc;6A6T?B`Qp%^<U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=Db!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vW>HF-Vi3+ZOI=+qP}n zw(+!WcTd~4ZJX1!ZM&y!+uyt=&i!+~d(V%GjH;-NsEEv6nS1TERt|RHh!0>W4+4pp z1-*EzAM~i`+1f(VEHI8So`S`akPfPTfq*`l{Fz`hS%k#JS0cjT2mS0#QLGf=J?1`he3W*;m4)ce8*WFq1sdP=~$5RlH1EdWm|~dCvKOi4*I_96{^95p#B<(n!d?B z=o`0{t+&OMwKcxiBECznJcfH!fL(z3OvmxP#oWd48|mMjpE||zdiTBdWelj8&Qosv zZFp@&UgXuvJw5y=q6*28AtxZzo-UUpkRW%ne+Ylf!V-0+uQXBW=5S1o#6LXNtY5!I z%Rkz#(S8Pjz*P7bqB6L|M#Er{|QLae-Y{KA>`^} z@lPjeX>90X|34S-7}ZVXe{wEei1<{*e8T-Nbj8JmD4iwcE+Hg_zhkPVm#=@b$;)h6 z<<6y`nPa`f3I6`!28d@kdM{uJOgM%`EvlQ5B2bL)Sl=|y@YB3KeOzz=9cUW3clPAU z^sYc}xf9{4Oj?L5MOlYxR{+>w=vJjvbyO5}ptT(o6dR|ygO$)nVCvNGnq(6;bHlBd zl?w-|plD8spjDF03g5ip;W3Z z><0{BCq!Dw;h5~#1BuQilq*TwEu)qy50@+BE4bX28+7erX{BD4H)N+7U`AVEuREE8 z;X?~fyhF-x_sRfHIj~6f(+^@H)D=ngP;mwJjxhQUbUdzk8f94Ab%59-eRIq?ZKrwD z(BFI=)xrUlgu(b|hAysqK<}8bslmNNeD=#JW*}^~Nrswn^xw*nL@Tx!49bfJecV&KC2G4q5a!NSv)06A_5N3Y?veAz;Gv+@U3R% z)~UA8-0LvVE{}8LVDOHzp~2twReqf}ODIyXMM6=W>kL|OHcx9P%+aJGYi_Om)b!xe zF40Vntn0+VP>o<$AtP&JANjXBn7$}C@{+@3I@cqlwR2MdwGhVPxlTIcRVu@Ho-wO` z_~Or~IMG)A_`6-p)KPS@cT9mu9RGA>dVh5wY$NM9-^c@N=hcNaw4ITjm;iWSP^ZX| z)_XpaI61<+La+U&&%2a z0za$)-wZP@mwSELo#3!PGTt$uy0C(nTT@9NX*r3Ctw6J~7A(m#8fE)0RBd`TdKfAT zCf@$MAxjP`O(u9s@c0Fd@|}UQ6qp)O5Q5DPCeE6mSIh|Rj{$cAVIWsA=xPKVKxdhg zLzPZ`3CS+KIO;T}0Ip!fAUaNU>++ZJZRk@I(h<)RsJUhZ&Ru9*!4Ptn;gX^~4E8W^TSR&~3BAZc#HquXn)OW|TJ`CTahk+{qe`5+ixON^zA9IFd8)kc%*!AiLu z>`SFoZ5bW-%7}xZ>gpJcx_hpF$2l+533{gW{a7ce^B9sIdmLrI0)4yivZ^(Vh@-1q zFT!NQK$Iz^xu%|EOK=n>ug;(7J4OnS$;yWmq>A;hsD_0oAbLYhW^1Vdt9>;(JIYjf zdb+&f&D4@4AS?!*XpH>8egQvSVX`36jMd>$+RgI|pEg))^djhGSo&#lhS~9%NuWfX zDDH;3T*GzRT@5=7ibO>N-6_XPBYxno@mD_3I#rDD?iADxX`! zh*v8^i*JEMzyN#bGEBz7;UYXki*Xr(9xXax(_1qVW=Ml)kSuvK$coq2A(5ZGhs_pF z$*w}FbN6+QDseuB9=fdp_MTs)nQf!2SlROQ!gBJBCXD&@-VurqHj0wm@LWX-TDmS= z71M__vAok|@!qgi#H&H%Vg-((ZfxPAL8AI{x|VV!9)ZE}_l>iWk8UPTGHs*?u7RfP z5MC&=c6X;XlUzrz5q?(!eO@~* zoh2I*%J7dF!!_!vXoSIn5o|wj1#_>K*&CIn{qSaRc&iFVxt*^20ngCL;QonIS>I5^ zMw8HXm>W0PGd*}Ko)f|~dDd%;Wu_RWI_d;&2g6R3S63Uzjd7dn%Svu-OKpx*o|N>F zZg=-~qLb~VRLpv`k zWSdfHh@?dp=s_X`{yxOlxE$4iuyS;Z-x!*E6eqmEm*j2bE@=ZI0YZ5%Yj29!5+J$4h{s($nakA`xgbO8w zi=*r}PWz#lTL_DSAu1?f%-2OjD}NHXp4pXOsCW;DS@BC3h-q4_l`<))8WgzkdXg3! zs1WMt32kS2E#L0p_|x+x**TFV=gn`m9BWlzF{b%6j-odf4{7a4y4Uaef@YaeuPhU8 zHBvRqN^;$Jizy+ z=zW{E5<>2gp$pH{M@S*!sJVQU)b*J5*bX4h>5VJve#Q6ga}cQ&iL#=(u+KroWrxa%8&~p{WEUF0il=db;-$=A;&9M{Rq`ouZ5m%BHT6%st%saGsD6)fQgLN}x@d3q>FC;=f%O3Cyg=Ke@Gh`XW za@RajqOE9UB6eE=zhG%|dYS)IW)&y&Id2n7r)6p_)vlRP7NJL(x4UbhlcFXWT8?K=%s7;z?Vjts?y2+r|uk8Wt(DM*73^W%pAkZa1Jd zNoE)8FvQA>Z`eR5Z@Ig6kS5?0h;`Y&OL2D&xnnAUzQz{YSdh0k zB3exx%A2TyI)M*EM6htrxSlep!Kk(P(VP`$p0G~f$smld6W1r_Z+o?=IB@^weq>5VYsYZZR@` z&XJFxd5{|KPZmVOSxc@^%71C@;z}}WhbF9p!%yLj3j%YOlPL5s>7I3vj25 z@xmf=*z%Wb4;Va6SDk9cv|r*lhZ`(y_*M@>q;wrn)oQx%B(2A$9(74>;$zmQ!4fN; z>XurIk-7@wZys<+7XL@0Fhe-f%*=(weaQEdR9Eh6>Kl-EcI({qoZqyzziGwpg-GM#251sK_ z=3|kitS!j%;fpc@oWn65SEL73^N&t>Ix37xgs= zYG%eQDJc|rqHFia0!_sm7`@lvcv)gfy(+KXA@E{3t1DaZ$DijWAcA)E0@X?2ziJ{v z&KOYZ|DdkM{}t+@{@*6ge}m%xfjIxi%qh`=^2Rwz@w0cCvZ&Tc#UmCDbVwABrON^x zEBK43FO@weA8s7zggCOWhMvGGE`baZ62cC)VHyy!5Zbt%ieH+XN|OLbAFPZWyC6)p z4P3%8sq9HdS3=ih^0OOlqTPbKuzQ?lBEI{w^ReUO{V?@`ARsL|S*%yOS=Z%sF)>-y z(LAQdhgAcuF6LQjRYfdbD1g4o%tV4EiK&ElLB&^VZHbrV1K>tHTO{#XTo>)2UMm`2 z^t4s;vnMQgf-njU-RVBRw0P0-m#d-u`(kq7NL&2T)TjI_@iKuPAK-@oH(J8?%(e!0Ir$yG32@CGUPn5w4)+9@8c&pGx z+K3GKESI4*`tYlmMHt@br;jBWTei&(a=iYslc^c#RU3Q&sYp zSG){)V<(g7+8W!Wxeb5zJb4XE{I|&Y4UrFWr%LHkdQ;~XU zgy^dH-Z3lmY+0G~?DrC_S4@=>0oM8Isw%g(id10gWkoz2Q%7W$bFk@mIzTCcIB(K8 zc<5h&ZzCdT=9n-D>&a8vl+=ZF*`uTvQviG_bLde*k>{^)&0o*b05x$MO3gVLUx`xZ z43j+>!u?XV)Yp@MmG%Y`+COH2?nQcMrQ%k~6#O%PeD_WvFO~Kct za4XoCM_X!c5vhRkIdV=xUB3xI2NNStK*8_Zl!cFjOvp-AY=D;5{uXj}GV{LK1~IE2 z|KffUiBaStRr;10R~K2VVtf{TzM7FaPm;Y(zQjILn+tIPSrJh&EMf6evaBKIvi42-WYU9Vhj~3< zZSM-B;E`g_o8_XTM9IzEL=9Lb^SPhe(f(-`Yh=X6O7+6ALXnTcUFpI>ekl6v)ZQeNCg2 z^H|{SKXHU*%nBQ@I3It0m^h+6tvI@FS=MYS$ZpBaG7j#V@P2ZuYySbp@hA# ze(kc;P4i_-_UDP?%<6>%tTRih6VBgScKU^BV6Aoeg6Uh(W^#J^V$Xo^4#Ekp ztqQVK^g9gKMTHvV7nb64UU7p~!B?>Y0oFH5T7#BSW#YfSB@5PtE~#SCCg3p^o=NkMk$<8- z6PT*yIKGrvne7+y3}_!AC8NNeI?iTY(&nakN>>U-zT0wzZf-RuyZk^X9H-DT_*wk= z;&0}6LsGtfVa1q)CEUPlx#(ED@-?H<1_FrHU#z5^P3lEB|qsxEyn%FOpjx z3S?~gvoXy~L(Q{Jh6*i~=f%9kM1>RGjBzQh_SaIDfSU_9!<>*Pm>l)cJD@wlyxpBV z4Fmhc2q=R_wHCEK69<*wG%}mgD1=FHi4h!98B-*vMu4ZGW~%IrYSLGU{^TuseqVgV zLP<%wirIL`VLyJv9XG_p8w@Q4HzNt-o;U@Au{7%Ji;53!7V8Rv0^Lu^Vf*sL>R(;c zQG_ZuFl)Mh-xEIkGu}?_(HwkB2jS;HdPLSxVU&Jxy9*XRG~^HY(f0g8Q}iqnVmgjI zfd=``2&8GsycjR?M%(zMjn;tn9agcq;&rR!Hp z$B*gzHsQ~aXw8c|a(L^LW(|`yGc!qOnV(ZjU_Q-4z1&0;jG&vAKuNG=F|H?@m5^N@ zq{E!1n;)kNTJ>|Hb2ODt-7U~-MOIFo%9I)_@7fnX+eMMNh>)V$IXesJpBn|uo8f~#aOFytCT zf9&%MCLf8mp4kwHTcojWmM3LU=#|{3L>E}SKwOd?%{HogCZ_Z1BSA}P#O(%H$;z7XyJ^sjGX;j5 zrzp>|Ud;*&VAU3x#f{CKwY7Vc{%TKKqmB@oTHA9;>?!nvMA;8+Jh=cambHz#J18x~ zs!dF>$*AnsQ{{82r5Aw&^7eRCdvcgyxH?*DV5(I$qXh^zS>us*I66_MbL8y4d3ULj z{S(ipo+T3Ag!+5`NU2sc+@*m{_X|&p#O-SAqF&g_n7ObB82~$p%fXA5GLHMC+#qqL zdt`sJC&6C2)=juQ_!NeD>U8lDVpAOkW*khf7MCcs$A(wiIl#B9HM%~GtQ^}yBPjT@ z+E=|A!Z?A(rwzZ;T}o6pOVqHzTr*i;Wrc%&36kc@jXq~+w8kVrs;%=IFdACoLAcCAmhFNpbP8;s`zG|HC2Gv?I~w4ITy=g$`0qMQdkijLSOtX6xW%Z9Nw<;M- zMN`c7=$QxN00DiSjbVt9Mi6-pjv*j(_8PyV-il8Q-&TwBwH1gz1uoxs6~uU}PrgWB zIAE_I-a1EqlIaGQNbcp@iI8W1sm9fBBNOk(k&iLBe%MCo#?xI$%ZmGA?=)M9D=0t7 zc)Q0LnI)kCy{`jCGy9lYX%mUsDWwsY`;jE(;Us@gmWPqjmXL+Hu#^;k%eT>{nMtzj zsV`Iy6leTA8-PndszF;N^X@CJrTw5IIm!GPeu)H2#FQitR{1p;MasQVAG3*+=9FYK zw*k!HT(YQorfQj+1*mCV458(T5=fH`um$gS38hw(OqVMyunQ;rW5aPbF##A3fGH6h z@W)i9Uff?qz`YbK4c}JzQpuxuE3pcQO)%xBRZp{zJ^-*|oryTxJ-rR+MXJ)!f=+pp z10H|DdGd2exhi+hftcYbM0_}C0ZI-2vh+$fU1acsB-YXid7O|=9L!3e@$H*6?G*Zp z%qFB(sgl=FcC=E4CYGp4CN>=M8#5r!RU!u+FJVlH6=gI5xHVD&k;Ta*M28BsxfMV~ zLz+@6TxnfLhF@5=yQo^1&S}cmTN@m!7*c6z;}~*!hNBjuE>NLVl2EwN!F+)0$R1S! zR|lF%n!9fkZ@gPW|x|B={V6x3`=jS*$Pu0+5OWf?wnIy>Y1MbbGSncpKO0qE(qO=ts z!~@&!N`10S593pVQu4FzpOh!tvg}p%zCU(aV5=~K#bKi zHdJ1>tQSrhW%KOky;iW+O_n;`l9~omqM%sdxdLtI`TrJzN6BQz+7xOl*rM>xVI2~# z)7FJ^Dc{DC<%~VS?@WXzuOG$YPLC;>#vUJ^MmtbSL`_yXtNKa$Hk+l-c!aC7gn(Cg ze?YPYZ(2Jw{SF6MiO5(%_pTo7j@&DHNW`|lD`~{iH+_eSTS&OC*2WTT*a`?|9w1dh zh1nh@$a}T#WE5$7Od~NvSEU)T(W$p$s5fe^GpG+7fdJ9=enRT9$wEk+ZaB>G3$KQO zgq?-rZZnIv!p#>Ty~}c*Lb_jxJg$eGM*XwHUwuQ|o^}b3^T6Bxx{!?va8aC@-xK*H ztJBFvFfsSWu89%@b^l3-B~O!CXs)I6Y}y#0C0U0R0WG zybjroj$io0j}3%P7zADXOwHwafT#uu*zfM!oD$6aJx7+WL%t-@6^rD_a_M?S^>c;z zMK580bZXo1f*L$CuMeM4Mp!;P@}b~$cd(s5*q~FP+NHSq;nw3fbWyH)i2)-;gQl{S zZO!T}A}fC}vUdskGSq&{`oxt~0i?0xhr6I47_tBc`fqaSrMOzR4>0H^;A zF)hX1nfHs)%Zb-(YGX;=#2R6C{BG;k=?FfP?9{_uFLri~-~AJ;jw({4MU7e*d)?P@ zXX*GkNY9ItFjhwgAIWq7Y!ksbMzfqpG)IrqKx9q{zu%Mdl+{Dis#p9q`02pr1LG8R z@As?eG!>IoROgS!@J*to<27coFc1zpkh?w=)h9CbYe%^Q!Ui46Y*HO0mr% zEff-*$ndMNw}H2a5@BsGj5oFfd!T(F&0$<{GO!Qdd?McKkorh=5{EIjDTHU`So>8V zBA-fqVLb2;u7UhDV1xMI?y>fe3~4urv3%PX)lDw+HYa;HFkaLqi4c~VtCm&Ca+9C~ zge+67hp#R9`+Euq59WhHX&7~RlXn=--m8$iZ~~1C8cv^2(qO#X0?vl91gzUKBeR1J z^p4!!&7)3#@@X&2aF2-)1Ffcc^F8r|RtdL2X%HgN&XU-KH2SLCbpw?J5xJ*!F-ypZ zMG%AJ!Pr&}`LW?E!K~=(NJxuSVTRCGJ$2a*Ao=uUDSys!OFYu!Vs2IT;xQ6EubLIl z+?+nMGeQQhh~??0!s4iQ#gm3!BpMpnY?04kK375e((Uc7B3RMj;wE?BCoQGu=UlZt!EZ1Q*auI)dj3Jj{Ujgt zW5hd~-HWBLI_3HuO) zNrb^XzPsTIb=*a69wAAA3J6AAZZ1VsYbIG}a`=d6?PjM)3EPaDpW2YP$|GrBX{q*! z$KBHNif)OKMBCFP5>!1d=DK>8u+Upm-{hj5o|Wn$vh1&K!lVfDB&47lw$tJ?d5|=B z^(_9=(1T3Fte)z^>|3**n}mIX;mMN5v2F#l(q*CvU{Ga`@VMp#%rQkDBy7kYbmb-q z<5!4iuB#Q_lLZ8}h|hPODI^U6`gzLJre9u3k3c#%86IKI*^H-@I48Bi*@avYm4v!n0+v zWu{M{&F8#p9cx+gF0yTB_<2QUrjMPo9*7^-uP#~gGW~y3nfPAoV%amgr>PSyVAd@l)}8#X zR5zV6t*uKJZL}?NYvPVK6J0v4iVpwiN|>+t3aYiZSp;m0!(1`bHO}TEtWR1tY%BPB z(W!0DmXbZAsT$iC13p4f>u*ZAy@JoLAkJhzFf1#4;#1deO8#8d&89}en&z!W&A3++^1(;>0SB1*54d@y&9Pn;^IAf3GiXbfT`_>{R+Xv; zQvgL>+0#8-laO!j#-WB~(I>l0NCMt_;@Gp_f0#^c)t?&#Xh1-7RR0@zPyBz!U#0Av zT?}n({(p?p7!4S2ZBw)#KdCG)uPnZe+U|0{BW!m)9 zi_9$F?m<`2!`JNFv+w8MK_K)qJ^aO@7-Ig>cM4-r0bi=>?B_2mFNJ}aE3<+QCzRr*NA!QjHw# z`1OsvcoD0?%jq{*7b!l|L1+Tw0TTAM4XMq7*ntc-Ived>Sj_ZtS|uVdpfg1_I9knY z2{GM_j5sDC7(W&}#s{jqbybqJWyn?{PW*&cQIU|*v8YGOKKlGl@?c#TCnmnAkAzV- zmK={|1G90zz=YUvC}+fMqts0d4vgA%t6Jhjv?d;(Z}(Ep8fTZfHA9``fdUHkA+z3+ zhh{ohP%Bj?T~{i0sYCQ}uC#5BwN`skI7`|c%kqkyWIQ;!ysvA8H`b-t()n6>GJj6xlYDu~8qX{AFo$Cm3d|XFL=4uvc?Keb zzb0ZmMoXca6Mob>JqkNuoP>B2Z>D`Q(TvrG6m`j}-1rGP!g|qoL=$FVQYxJQjFn33lODt3Wb1j8VR zlR++vIT6^DtYxAv_hxupbLLN3e0%A%a+hWTKDV3!Fjr^cWJ{scsAdfhpI)`Bms^M6 zQG$waKgFr=c|p9Piug=fcJvZ1ThMnNhQvBAg-8~b1?6wL*WyqXhtj^g(Ke}mEfZVM zJuLNTUVh#WsE*a6uqiz`b#9ZYg3+2%=C(6AvZGc=u&<6??!slB1a9K)=VL zY9EL^mfyKnD zSJyYBc_>G;5RRnrNgzJz#Rkn3S1`mZgO`(r5;Hw6MveN(URf_XS-r58Cn80K)ArH4 z#Rrd~LG1W&@ttw85cjp8xV&>$b%nSXH_*W}7Ch2pg$$c0BdEo-HWRTZcxngIBJad> z;C>b{jIXjb_9Jis?NZJsdm^EG}e*pR&DAy0EaSGi3XWTa(>C%tz1n$u?5Fb z1qtl?;_yjYo)(gB^iQq?=jusF%kywm?CJP~zEHi0NbZ);$(H$w(Hy@{i>$wcVRD_X|w-~(0Z9BJyh zhNh;+eQ9BEIs;tPz%jSVnfCP!3L&9YtEP;svoj_bNzeGSQIAjd zBss@A;)R^WAu-37RQrM%{DfBNRx>v!G31Z}8-El9IOJlb_MSoMu2}GDYycNaf>uny z+8xykD-7ONCM!APry_Lw6-yT>5!tR}W;W`C)1>pxSs5o1z#j7%m=&=7O4hz+Lsqm` z*>{+xsabZPr&X=}G@obTb{nPTkccJX8w3CG7X+1+t{JcMabv~UNv+G?txRqXib~c^Mo}`q{$`;EBNJ;#F*{gvS12kV?AZ%O0SFB$^ zn+}!HbmEj}w{Vq(G)OGAzH}R~kS^;(-s&=ectz8vN!_)Yl$$U@HNTI-pV`LSj7Opu zTZ5zZ)-S_{GcEQPIQXLQ#oMS`HPu{`SQiAZ)m1at*Hy%3xma|>o`h%E%8BEbi9p0r zVjcsh<{NBKQ4eKlXU|}@XJ#@uQw*$4BxKn6#W~I4T<^f99~(=}a`&3(ur8R9t+|AQ zWkQx7l}wa48-jO@ft2h+7qn%SJtL%~890FG0s5g*kNbL3I&@brh&f6)TlM`K^(bhr zJWM6N6x3flOw$@|C@kPi7yP&SP?bzP-E|HSXQXG>7gk|R9BTj`e=4de9C6+H7H7n# z#GJeVs1mtHhLDmVO?LkYRQc`DVOJ_vdl8VUihO-j#t=0T3%Fc1f9F73ufJz*adn*p zc%&vi(4NqHu^R>sAT_0EDjVR8bc%wTz#$;%NU-kbDyL_dg0%TFafZwZ?5KZpcuaO54Z9hX zD$u>q!-9`U6-D`E#`W~fIfiIF5_m6{fvM)b1NG3xf4Auw;Go~Fu7cth#DlUn{@~yu z=B;RT*dp?bO}o%4x7k9v{r=Y@^YQ^UUm(Qmliw8brO^=NP+UOohLYiaEB3^DB56&V zK?4jV61B|1Uj_5fBKW;8LdwOFZKWp)g{B%7g1~DgO&N& z#lisxf?R~Z@?3E$Mms$$JK8oe@X`5m98V*aV6Ua}8Xs2#A!{x?IP|N(%nxsH?^c{& z@vY&R1QmQs83BW28qAmJfS7MYi=h(YK??@EhjL-t*5W!p z^gYX!Q6-vBqcv~ruw@oMaU&qp0Fb(dbVzm5xJN%0o_^@fWq$oa3X?9s%+b)x4w-q5Koe(@j6Ez7V@~NRFvd zfBH~)U5!ix3isg`6be__wBJp=1@yfsCMw1C@y+9WYD9_C%{Q~7^0AF2KFryfLlUP# zwrtJEcH)jm48!6tUcxiurAMaiD04C&tPe6DI0#aoqz#Bt0_7_*X*TsF7u*zv(iEfA z;$@?XVu~oX#1YXtceQL{dSneL&*nDug^OW$DSLF0M1Im|sSX8R26&)<0Fbh^*l6!5wfSu8MpMoh=2l z^^0Sr$UpZp*9oqa23fcCfm7`ya2<4wzJ`Axt7e4jJrRFVf?nY~2&tRL* zd;6_njcz01c>$IvN=?K}9ie%Z(BO@JG2J}fT#BJQ+f5LFSgup7i!xWRKw6)iITjZU z%l6hPZia>R!`aZjwCp}I zg)%20;}f+&@t;(%5;RHL>K_&7MH^S+7<|(SZH!u zznW|jz$uA`P9@ZWtJgv$EFp>)K&Gt+4C6#*khZQXS*S~6N%JDT$r`aJDs9|uXWdbg zBwho$phWx}x!qy8&}6y5Vr$G{yGSE*r$^r{}pw zVTZKvikRZ`J_IJrjc=X1uw?estdwm&bEahku&D04HD+0Bm~q#YGS6gp!KLf$A{%Qd z&&yX@Hp>~(wU{|(#U&Bf92+1i&Q*-S+=y=3pSZy$#8Uc$#7oiJUuO{cE6=tsPhwPe| zxQpK>`Dbka`V)$}e6_OXKLB%i76~4N*zA?X+PrhH<&)}prET;kel24kW%+9))G^JI zsq7L{P}^#QsZViX%KgxBvEugr>ZmFqe^oAg?{EI=&_O#e)F3V#rc z8$4}0Zr19qd3tE4#$3_f=Bbx9oV6VO!d3(R===i-7p=Vj`520w0D3W6lQfY48}!D* z&)lZMG;~er2qBoI2gsX+Ts-hnpS~NYRDtPd^FPzn!^&yxRy#CSz(b&E*tL|jIkq|l zf%>)7Dtu>jCf`-7R#*GhGn4FkYf;B$+9IxmqH|lf6$4irg{0ept__%)V*R_OK=T06 zyT_m-o@Kp6U{l5h>W1hGq*X#8*y@<;vsOFqEjTQXFEotR+{3}ODDnj;o0@!bB5x=N z394FojuGOtVKBlVRLtHp%EJv_G5q=AgF)SKyRN5=cGBjDWv4LDn$IL`*=~J7u&Dy5 zrMc83y+w^F&{?X(KOOAl-sWZDb{9X9#jrQtmrEXD?;h-}SYT7yM(X_6qksM=K_a;Z z3u0qT0TtaNvDER_8x*rxXw&C^|h{P1qxK|@pS7vdlZ#P z7PdB7MmC2}%sdzAxt>;WM1s0??`1983O4nFK|hVAbHcZ3x{PzytQLkCVk7hA!Lo` zEJH?4qw|}WH{dc4z%aB=0XqsFW?^p=X}4xnCJXK%c#ItOSjdSO`UXJyuc8bh^Cf}8 z@Ht|vXd^6{Fgai8*tmyRGmD_s_nv~r^Fy7j`Bu`6=G)5H$i7Q7lvQnmea&TGvJp9a|qOrUymZ$6G|Ly z#zOCg++$3iB$!6!>215A4!iryregKuUT344X)jQb3|9qY>c0LO{6Vby05n~VFzd?q zgGZv&FGlkiH*`fTurp>B8v&nSxNz)=5IF$=@rgND4d`!AaaX;_lK~)-U8la_Wa8i?NJC@BURO*sUW)E9oyv3RG^YGfN%BmxzjlT)bp*$<| zX3tt?EAy<&K+bhIuMs-g#=d1}N_?isY)6Ay$mDOKRh z4v1asEGWoAp=srraLW^h&_Uw|6O+r;wns=uwYm=JN4Q!quD8SQRSeEcGh|Eb5Jg8m zOT}u;N|x@aq)=&;wufCc^#)5U^VcZw;d_wwaoh9$p@Xrc{DD6GZUqZ ziC6OT^zSq@-lhbgR8B+e;7_Giv;DK5gn^$bs<6~SUadiosfewWDJu`XsBfOd1|p=q zE>m=zF}!lObA%ePey~gqU8S6h-^J2Y?>7)L2+%8kV}Gp=h`Xm_}rlm)SyUS=`=S7msKu zC|T!gPiI1rWGb1z$Md?0YJQ;%>uPLOXf1Z>N~`~JHJ!^@D5kSXQ4ugnFZ>^`zH8CAiZmp z6Ms|#2gcGsQ{{u7+Nb9sA?U>(0e$5V1|WVwY`Kn)rsnnZ4=1u=7u!4WexZD^IQ1Jk zfF#NLe>W$3m&C^ULjdw+5|)-BSHwpegdyt9NYC{3@QtMfd8GrIWDu`gd0nv-3LpGCh@wgBaG z176tikL!_NXM+Bv#7q^cyn9$XSeZR6#!B4JE@GVH zoobHZN_*RF#@_SVYKkQ_igme-Y5U}cV(hkR#k1c{bQNMji zU7aE`?dHyx=1`kOYZo_8U7?3-7vHOp`Qe%Z*i+FX!s?6huNp0iCEW-Z7E&jRWmUW_ z67j>)Ew!yq)hhG4o?^z}HWH-e=es#xJUhDRc4B51M4~E-l5VZ!&zQq`gWe`?}#b~7w1LH4Xa-UCT5LXkXQWheBa2YJYbyQ zl1pXR%b(KCXMO0OsXgl0P0Og<{(@&z1aokU-Pq`eQq*JYgt8xdFQ6S z6Z3IFSua8W&M#`~*L#r>Jfd6*BzJ?JFdBR#bDv$_0N!_5vnmo@!>vULcDm`MFU823 zpG9pqjqz^FE5zMDoGqhs5OMmC{Y3iVcl>F}5Rs24Y5B^mYQ;1T&ks@pIApHOdrzXF z-SdX}Hf{X;TaSxG_T$0~#RhqKISGKNK47}0*x&nRIPtmdwxc&QT3$8&!3fWu1eZ_P zJveQj^hJL#Sn!*4k`3}(d(aasl&7G0j0-*_2xtAnoX1@9+h zO#c>YQg60Z;o{Bi=3i7S`Ic+ZE>K{(u|#)9y}q*j8uKQ1^>+(BI}m%1v3$=4ojGBc zm+o1*!T&b}-lVvZqIUBc8V}QyFEgm#oyIuC{8WqUNV{Toz`oxhYpP!_p2oHHh5P@iB*NVo~2=GQm+8Yrkm2Xjc_VyHg1c0>+o~@>*Qzo zHVBJS>$$}$_4EniTI;b1WShX<5-p#TPB&!;lP!lBVBbLOOxh6FuYloD%m;n{r|;MU3!q4AVkua~fieeWu2 zQAQ$ue(IklX6+V;F1vCu-&V?I3d42FgWgsb_e^29ol}HYft?{SLf>DrmOp9o!t>I^ zY7fBCk+E8n_|apgM|-;^=#B?6RnFKlN`oR)`e$+;D=yO-(U^jV;rft^G_zl`n7qnM zL z*-Y4Phq+ZI1$j$F-f;`CD#|`-T~OM5Q>x}a>B~Gb3-+9i>Lfr|Ca6S^8g*{*?_5!x zH_N!SoRP=gX1?)q%>QTY!r77e2j9W(I!uAz{T`NdNmPBBUzi2{`XMB^zJGGwFWeA9 z{fk33#*9SO0)DjROug+(M)I-pKA!CX;IY(#gE!UxXVsa)X!UftIN98{pt#4MJHOhY zM$_l}-TJlxY?LS6Nuz1T<44m<4i^8k@D$zuCPrkmz@sdv+{ciyFJG2Zwy&%c7;atIeTdh!a(R^QXnu1Oq1b42*OQFWnyQ zWeQrdvP|w_idy53Wa<{QH^lFmEd+VlJkyiC>6B#s)F;w-{c;aKIm;Kp50HnA-o3lY z9B~F$gJ@yYE#g#X&3ADx&tO+P_@mnQTz9gv30_sTsaGXkfNYXY{$(>*PEN3QL>I!k zp)KibPhrfX3%Z$H6SY`rXGYS~143wZrG2;=FLj50+VM6soI~up_>fU(2Wl@{BRsMi zO%sL3x?2l1cXTF)k&moNsHfQrQ+wu(gBt{sk#CU=UhrvJIncy@tJX5klLjgMn>~h= zg|FR&;@eh|C7`>s_9c~0-{IAPV){l|Ts`i=)AW;d9&KPc3fMeoTS%8@V~D8*h;&(^>yjT84MM}=%#LS7shLAuuj(0VAYoozhWjq z4LEr?wUe2^WGwdTIgWBkDUJa>YP@5d9^Rs$kCXmMRxuF*YMVrn?0NFyPl}>`&dqZb z<5eqR=ZG3>n2{6v6BvJ`YBZeeTtB88TAY(x0a58EWyuf>+^|x8Qa6wA|1Nb_p|nA zWWa}|z8a)--Wj`LqyFk_a3gN2>5{Rl_wbW?#by7&i*^hRknK%jwIH6=dQ8*-_{*x0j^DUfMX0`|K@6C<|1cgZ~D(e5vBFFm;HTZF(!vT8=T$K+|F)x3kqzBV4-=p1V(lzi(s7jdu0>LD#N=$Lk#3HkG!a zIF<7>%B7sRNzJ66KrFV76J<2bdYhxll0y2^_rdG=I%AgW4~)1Nvz=$1UkE^J%BxLo z+lUci`UcU062os*=`-j4IfSQA{w@y|3}Vk?i;&SSdh8n+$iHA#%ERL{;EpXl6u&8@ zzg}?hkEOUOJt?ZL=pWZFJ19mI1@P=$U5*Im1e_8Z${JsM>Ov?nh8Z zP5QvI!{Jy@&BP48%P2{Jr_VgzW;P@7)M9n|lDT|Ep#}7C$&ud&6>C^5ZiwKIg2McPU(4jhM!BD@@L(Gd*Nu$ji(ljZ<{FIeW_1Mmf;76{LU z-ywN~=uNN)Xi6$<12A9y)K%X|(W0p|&>>4OXB?IiYr||WKDOJPxiSe01NSV-h24^L z_>m$;|C+q!Mj**-qQ$L-*++en(g|hw;M!^%_h-iDjFHLo-n3JpB;p?+o2;`*jpvJU zLY^lt)Un4joij^^)O(CKs@7E%*!w>!HA4Q?0}oBJ7Nr8NQ7QmY^4~jvf0-`%waOLn zdNjAPaC0_7c|RVhw)+71NWjRi!y>C+Bl;Z`NiL^zn2*0kmj5gyhCLCxts*cWCdRI| zjsd=sT5BVJc^$GxP~YF$-U{-?kW6r@^vHXB%{CqYzU@1>dzf#3SYedJG-Rm6^RB7s zGM5PR(yKPKR)>?~vpUIeTP7A1sc8-knnJk*9)3t^e%izbdm>Y=W{$wm(cy1RB-19i za#828DMBY+ps#7Y8^6t)=Ea@%Nkt)O6JCx|ybC;Ap}Z@Zw~*}3P>MZLPb4Enxz9Wf zssobT^(R@KuShj8>@!1M7tm|2%-pYYDxz-5`rCbaTCG5{;Uxm z*g=+H1X8{NUvFGzz~wXa%Eo};I;~`37*WrRU&K0dPSB$yk(Z*@K&+mFal^?c zurbqB-+|Kb5|sznT;?Pj!+kgFY1#Dr;_%A(GIQC{3ct|{*Bji%FNa6c-thbpBkA;U zURV!Dr&X{0J}iht#-Qp2=xzuh(fM>zRoiGrYl5ttw2#r34gC41CCOC31m~^UPTK@s z6;A@)7O7_%C)>bnAXerYuAHdE93>j2N}H${zEc6&SbZ|-fiG*-qtGuy-qDelH(|u$ zorf8_T6Zqe#Ub!+e3oSyrskt_HyW_^5lrWt#30l)tHk|j$@YyEkXUOV;6B51L;M@=NIWZXU;GrAa(LGxO%|im%7F<-6N;en0Cr zLH>l*y?pMwt`1*cH~LdBPFY_l;~`N!Clyfr;7w<^X;&(ZiVdF1S5e(+Q%60zgh)s4 zn2yj$+mE=miVERP(g8}G4<85^-5f@qxh2ec?n+$A_`?qN=iyT1?U@t?V6DM~BIlBB z>u~eXm-aE>R0sQy!-I4xtCNi!!qh?R1!kKf6BoH2GG{L4%PAz0{Sh6xpuyI%*~u)s z%rLuFl)uQUCBQAtMyN;%)zFMx4loh7uTfKeB2Xif`lN?2gq6NhWhfz0u5WP9J>=V2 zo{mLtSy&BA!mSzs&CrKWq^y40JF5a&GSXIi2= z{EYb59J4}VwikL4P=>+mc6{($FNE@e=VUwG+KV21;<@lrN`mnz5jYGASyvz7BOG_6(p^eTxD-4O#lROgon;R35=|nj#eHIfJBYPWG>H>`dHKCDZ3`R{-?HO0mE~(5_WYcFmp8sU?wr*UkAQiNDGc6T zA%}GOLXlOWqL?WwfHO8MB#8M8*~Y*gz;1rWWoVSXP&IbKxbQ8+s%4Jnt?kDsq7btI zCDr0PZ)b;B%!lu&CT#RJzm{l{2fq|BcY85`w~3LSK<><@(2EdzFLt9Y_`;WXL6x`0 zDoQ?=?I@Hbr;*VVll1Gmd8*%tiXggMK81a+T(5Gx6;eNb8=uYn z5BG-0g>pP21NPn>$ntBh>`*})Fl|38oC^9Qz>~MAazH%3Q~Qb!ALMf$srexgPZ2@&c~+hxRi1;}+)-06)!#Mq<6GhP z-Q?qmgo${aFBApb5p}$1OJKTClfi8%PpnczyVKkoHw7Ml9e7ikrF0d~UB}i3vizos zXW4DN$SiEV9{faLt5bHy2a>33K%7Td-n5C*N;f&ZqAg#2hIqEb(y<&f4u5BWJ>2^4 z414GosL=Aom#m&=x_v<0-fp1r%oVJ{T-(xnomNJ(Dryv zh?vj+%=II_nV+@NR+(!fZZVM&(W6{6%9cm+o+Z6}KqzLw{(>E86uA1`_K$HqINlb1 zKelh3-jr2I9V?ych`{hta9wQ2c9=MM`2cC{m6^MhlL2{DLv7C^j z$xXBCnDl_;l|bPGMX@*tV)B!c|4oZyftUlP*?$YU9C_eAsuVHJ58?)zpbr30P*C`T z7y#ao`uE-SOG(Pi+`$=e^mle~)pRrdwL5)N;o{gpW21of(QE#U6w%*C~`v-z0QqBML!!5EeYA5IQB0 z^l01c;L6E(iytN!LhL}wfwP7W9PNAkb+)Cst?qg#$n;z41O4&v+8-zPs+XNb-q zIeeBCh#ivnFLUCwfS;p{LC0O7tm+Sf9Jn)~b%uwP{%69;QC)Ok0t%*a5M+=;y8j=v z#!*pp$9@!x;UMIs4~hP#pnfVc!%-D<+wsG@R2+J&%73lK|2G!EQC)O05TCV=&3g)C!lT=czLpZ@Sa%TYuoE?v8T8`V;e$#Zf2_Nj6nvBgh1)2 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..cea7a79 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..f3b75f3 --- /dev/null +++ b/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/scripts/build b/scripts/build new file mode 100755 index 0000000..f406348 --- /dev/null +++ b/scripts/build @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Building classes" +./gradlew build testClasses -x test diff --git a/scripts/fast-format b/scripts/fast-format new file mode 100755 index 0000000..1b3bc47 --- /dev/null +++ b/scripts/fast-format @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -euo pipefail + +echo "Script started with $# arguments" +echo "Arguments: $*" +echo "Script location: $(dirname "$0")" + +cd "$(dirname "$0")/.." +echo "Changed to directory: $(pwd)" + +if [ $# -eq 0 ]; then + echo "Usage: $0 [additional-formatter-args...]" + echo "The file should contain one file path per line" + exit 1 +fi + +FILE_LIST="$1" + +echo "Looking for file: $FILE_LIST" + +if [ ! -f "$FILE_LIST" ]; then + echo "Error: File '$FILE_LIST' not found" + exit 1 +fi + +if ! command -v ktfmt-fast-format &> /dev/null; then + echo "Error: ktfmt-fast-format not found" + exit 1 +fi + +# Process Kotlin files +echo "==> Looking for Kotlin files" +kt_files=$(grep -E '\.kt$' "$FILE_LIST" | grep -v './buildSrc/build/' || true) +echo "==> Done looking for Kotlin files" + +if [[ -n "$kt_files" ]]; then + echo "==> will format Kotlin files" + echo "$kt_files" | tr '\n' '\0' | xargs -0 ktfmt-fast-format --kotlinlang-style "$@" +else + echo "No Kotlin files to format -- expected outcome during incremental formatting" +fi + +# TODO(mbudayr): support palantir-java-format +# Process Java files +# grep -E '\.java$' "$FILE_LIST" | grep -v './buildSrc/build/' | tr '\n' '\0' | xargs -0 -r palantir-java-format --palantir --replace "$@" diff --git a/scripts/format b/scripts/format new file mode 100755 index 0000000..65db176 --- /dev/null +++ b/scripts/format @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if command -v ktfmt &> /dev/null; then + echo "==> Running ktfmt" + ./scripts/kotlin-format +else + echo "==> Running gradlew formatKotlin" + ./gradlew formatKotlin +fi + +if command -v palantir-java-format &> /dev/null; then + echo "==> Running palantir-java-format" + ./scripts/java-format +else + echo "==> Running gradlew formatJava" + ./gradlew formatJava +fi diff --git a/scripts/java-format b/scripts/java-format new file mode 100755 index 0000000..ad5febc --- /dev/null +++ b/scripts/java-format @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +find . -name "*.java" -not -path "./buildSrc/build/*" -print0 | xargs -0 -r palantir-java-format --palantir --replace "$@" diff --git a/scripts/kotlin-format b/scripts/kotlin-format new file mode 100755 index 0000000..3b8be9e --- /dev/null +++ b/scripts/kotlin-format @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +find . -name "*.kt" -not -path "./buildSrc/build/*" -print0 | xargs -0 -r ktfmt --kotlinlang-style "$@" diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 0000000..dbc8f77 --- /dev/null +++ b/scripts/lint @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running lints" + +if command -v ktfmt &> /dev/null; then + echo "==> Checking ktfmt" + ./scripts/kotlin-format --dry-run --set-exit-if-changed +else + echo "==> Running gradlew lintKotlin" + ./gradlew lintKotlin +fi + +if command -v palantir-java-format &> /dev/null; then + echo "==> Checking palantir-java-format" + ./scripts/java-format --dry-run --set-exit-if-changed +else + echo "==> Running gradlew lintJava" + ./gradlew lintJava +fi diff --git a/scripts/mock b/scripts/mock new file mode 100755 index 0000000..0b28f6e --- /dev/null +++ b/scripts/mock @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [[ -n "$1" && "$1" != '--'* ]]; then + URL="$1" + shift +else + URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" +fi + +# Check if the URL is empty +if [ -z "$URL" ]; then + echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" + exit 1 +fi + +echo "==> Starting mock server with URL ${URL}" + +# Run prism mock on the given spec +if [ "$1" == "--daemon" ]; then + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + + # Wait for server to come online + echo -n "Waiting for server" + while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + echo -n "." + sleep 0.1 + done + + if grep -q "✖ fatal" ".prism.log"; then + cat .prism.log + exit 1 + fi + + echo +else + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..047bc1d --- /dev/null +++ b/scripts/test @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +function prism_is_running() { + curl --silent "http://localhost:4010" >/dev/null 2>&1 +} + +kill_server_on_port() { + pids=$(lsof -t -i tcp:"$1" || echo "") + if [ "$pids" != "" ]; then + kill "$pids" + echo "Stopped $pids." + fi +} + +function is_overriding_api_base_url() { + [ -n "$TEST_API_BASE_URL" ] +} + +if ! is_overriding_api_base_url && ! prism_is_running ; then + # When we exit this script, make sure to kill the background mock server process + trap 'kill_server_on_port 4010' EXIT + + # Start the dev server + ./scripts/mock --daemon +fi + +if is_overriding_api_base_url ; then + echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" + echo +elif ! prism_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" + echo -e "running against your OpenAPI spec." + echo + echo -e "To run the server, pass in the path or url of your OpenAPI" + echo -e "spec to the prism command:" + echo + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo + + exit 1 +else + echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo +fi + +echo "==> Running tests" +./gradlew test "$@" diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..02623dd --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,14 @@ +rootProject.name = "stagehand-java-root" + +val projectNames = rootDir.listFiles() + ?.asSequence() + .orEmpty() + .filter { file -> + file.isDirectory && + file.name.startsWith("stagehand-java") && + file.listFiles()?.asSequence().orEmpty().any { it.name == "build.gradle.kts" } + } + .map { it.name } + .toList() +println("projects: $projectNames") +projectNames.forEach { include(it) } diff --git a/stagehand-java-client-okhttp/build.gradle.kts b/stagehand-java-client-okhttp/build.gradle.kts new file mode 100644 index 0000000..cb49933 --- /dev/null +++ b/stagehand-java-client-okhttp/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("stagehand.kotlin") + id("stagehand.publish") +} + +dependencies { + api(project(":stagehand-java-core")) + + implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") + + testImplementation(kotlin("test")) + testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") +} diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt new file mode 100644 index 0000000..7db7941 --- /dev/null +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt @@ -0,0 +1,252 @@ +package com.stagehand.api.client.okhttp + +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.Timeout +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.HttpClient +import com.stagehand.api.core.http.HttpMethod +import com.stagehand.api.core.http.HttpRequest +import com.stagehand.api.core.http.HttpRequestBody +import com.stagehand.api.core.http.HttpResponse +import com.stagehand.api.errors.StagehandIoException +import java.io.IOException +import java.io.InputStream +import java.net.Proxy +import java.time.Duration +import java.util.concurrent.CancellationException +import java.util.concurrent.CompletableFuture +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager +import okhttp3.Call +import okhttp3.Callback +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import okhttp3.Response +import okhttp3.logging.HttpLoggingInterceptor +import okio.BufferedSink + +class OkHttpClient +private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { + + override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { + val call = newCall(request, requestOptions) + + return try { + call.execute().toResponse() + } catch (e: IOException) { + throw StagehandIoException("Request failed", e) + } finally { + request.body?.close() + } + } + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture { + val future = CompletableFuture() + + val call = newCall(request, requestOptions) + call.enqueue( + object : Callback { + override fun onResponse(call: Call, response: Response) { + future.complete(response.toResponse()) + } + + override fun onFailure(call: Call, e: IOException) { + future.completeExceptionally(StagehandIoException("Request failed", e)) + } + } + ) + + future.whenComplete { _, e -> + if (e is CancellationException) { + call.cancel() + } + request.body?.close() + } + + return future + } + + override fun close() { + okHttpClient.dispatcher.executorService.shutdown() + okHttpClient.connectionPool.evictAll() + okHttpClient.cache?.close() + } + + private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call { + val clientBuilder = okHttpClient.newBuilder() + + val logLevel = + when (System.getenv("STAGEHAND_LOG")?.lowercase()) { + "info" -> HttpLoggingInterceptor.Level.BASIC + "debug" -> HttpLoggingInterceptor.Level.BODY + else -> null + } + if (logLevel != null) { + clientBuilder.addNetworkInterceptor( + HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") } + ) + } + + requestOptions.timeout?.let { + clientBuilder + .connectTimeout(it.connect()) + .readTimeout(it.read()) + .writeTimeout(it.write()) + .callTimeout(it.request()) + } + + val client = clientBuilder.build() + return client.newCall(request.toRequest(client)) + } + + private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient): Request { + var body: RequestBody? = body?.toRequestBody() + if (body == null && requiresBody(method)) { + body = "".toRequestBody() + } + + val builder = Request.Builder().url(toUrl()).method(method.name, body) + headers.names().forEach { name -> + headers.values(name).forEach { builder.addHeader(name, it) } + } + + if ( + !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0 + ) { + builder.addHeader( + "X-Stainless-Read-Timeout", + Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(), + ) + } + if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) { + builder.addHeader( + "X-Stainless-Timeout", + Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(), + ) + } + + return builder.build() + } + + /** `OkHttpClient` always requires a request body for some methods. */ + private fun requiresBody(method: HttpMethod): Boolean = + when (method) { + HttpMethod.POST, + HttpMethod.PUT, + HttpMethod.PATCH -> true + else -> false + } + + private fun HttpRequest.toUrl(): String { + val builder = baseUrl.toHttpUrl().newBuilder() + pathSegments.forEach(builder::addPathSegment) + queryParams.keys().forEach { key -> + queryParams.values(key).forEach { builder.addQueryParameter(key, it) } + } + + return builder.toString() + } + + private fun HttpRequestBody.toRequestBody(): RequestBody { + val mediaType = contentType()?.toMediaType() + val length = contentLength() + + return object : RequestBody() { + override fun contentType(): MediaType? = mediaType + + override fun contentLength(): Long = length + + override fun isOneShot(): Boolean = !repeatable() + + override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream()) + } + } + + private fun Response.toResponse(): HttpResponse { + val headers = headers.toHeaders() + + return object : HttpResponse { + override fun statusCode(): Int = code + + override fun headers(): Headers = headers + + override fun body(): InputStream = body!!.byteStream() + + override fun close() = body!!.close() + } + } + + private fun okhttp3.Headers.toHeaders(): Headers { + val headersBuilder = Headers.builder() + forEach { (name, value) -> headersBuilder.put(name, value) } + return headersBuilder.build() + } + + companion object { + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + + private var timeout: Timeout = Timeout.default() + private var proxy: Proxy? = null + private var sslSocketFactory: SSLSocketFactory? = null + private var trustManager: X509TrustManager? = null + private var hostnameVerifier: HostnameVerifier? = null + + fun timeout(timeout: Timeout) = apply { this.timeout = timeout } + + fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build()) + + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { + this.sslSocketFactory = sslSocketFactory + } + + fun trustManager(trustManager: X509TrustManager?) = apply { + this.trustManager = trustManager + } + + fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply { + this.hostnameVerifier = hostnameVerifier + } + + fun build(): OkHttpClient = + OkHttpClient( + okhttp3.OkHttpClient.Builder() + .connectTimeout(timeout.connect()) + .readTimeout(timeout.read()) + .writeTimeout(timeout.write()) + .callTimeout(timeout.request()) + .proxy(proxy) + .apply { + val sslSocketFactory = sslSocketFactory + val trustManager = trustManager + if (sslSocketFactory != null && trustManager != null) { + sslSocketFactory(sslSocketFactory, trustManager) + } else { + check((sslSocketFactory != null) == (trustManager != null)) { + "Both or none of `sslSocketFactory` and `trustManager` must be set, but only one was set" + } + } + + hostnameVerifier?.let(::hostnameVerifier) + } + .build() + .apply { + // We usually make all our requests to the same host so it makes sense to + // raise the per-host limit to the overall limit. + dispatcher.maxRequestsPerHost = dispatcher.maxRequests + } + ) + } +} diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt new file mode 100644 index 0000000..4b6805e --- /dev/null +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt @@ -0,0 +1,316 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.client.okhttp + +import com.fasterxml.jackson.databind.json.JsonMapper +import com.stagehand.api.client.StagehandClient +import com.stagehand.api.client.StagehandClientImpl +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.Sleeper +import com.stagehand.api.core.Timeout +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.HttpClient +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.core.jsonMapper +import java.net.Proxy +import java.time.Clock +import java.time.Duration +import java.util.Optional +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager +import kotlin.jvm.optionals.getOrNull + +/** + * A class that allows building an instance of [StagehandClient] with [OkHttpClient] as the + * underlying [HttpClient]. + */ +class StagehandOkHttpClient private constructor() { + + companion object { + + /** Returns a mutable builder for constructing an instance of [StagehandClient]. */ + @JvmStatic fun builder() = Builder() + + /** + * Returns a client configured using system properties and environment variables. + * + * @see ClientOptions.Builder.fromEnv + */ + @JvmStatic fun fromEnv(): StagehandClient = builder().fromEnv().build() + } + + /** A builder for [StagehandOkHttpClient]. */ + class Builder internal constructor() { + + private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var proxy: Proxy? = null + private var sslSocketFactory: SSLSocketFactory? = null + private var trustManager: X509TrustManager? = null + private var hostnameVerifier: HostnameVerifier? = null + + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + + /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ + fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + + /** + * The socket factory used to secure HTTPS connections. + * + * If this is set, then [trustManager] must also be set. + * + * If unset, then the system default is used. Most applications should not call this method, + * and instead use the system default. The default include special optimizations that can be + * lost if the implementation is modified. + */ + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { + this.sslSocketFactory = sslSocketFactory + } + + /** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */ + fun sslSocketFactory(sslSocketFactory: Optional) = + sslSocketFactory(sslSocketFactory.getOrNull()) + + /** + * The trust manager used to secure HTTPS connections. + * + * If this is set, then [sslSocketFactory] must also be set. + * + * If unset, then the system default is used. Most applications should not call this method, + * and instead use the system default. The default include special optimizations that can be + * lost if the implementation is modified. + */ + fun trustManager(trustManager: X509TrustManager?) = apply { + this.trustManager = trustManager + } + + /** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */ + fun trustManager(trustManager: Optional) = + trustManager(trustManager.getOrNull()) + + /** + * The verifier used to confirm that response certificates apply to requested hostnames for + * HTTPS connections. + * + * If unset, then a default hostname verifier is used. + */ + fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply { + this.hostnameVerifier = hostnameVerifier + } + + /** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */ + fun hostnameVerifier(hostnameVerifier: Optional) = + hostnameVerifier(hostnameVerifier.getOrNull()) + + /** + * Whether to throw an exception if any of the Jackson versions detected at runtime are + * incompatible with the SDK's minimum supported Jackson version (2.13.4). + * + * Defaults to true. Use extreme caution when disabling this option. There is no guarantee + * that the SDK will work correctly when using an incompatible Jackson version. + */ + fun checkJacksonVersionCompatibility(checkJacksonVersionCompatibility: Boolean) = apply { + clientOptions.checkJacksonVersionCompatibility(checkJacksonVersionCompatibility) + } + + /** + * The Jackson JSON mapper to use for serializing and deserializing JSON. + * + * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and + * rarely needs to be overridden. + */ + fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } + + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) } + + /** + * The clock to use for operations that require timing, like retries. + * + * This is primarily useful for using a fake clock in tests. + * + * Defaults to [Clock.systemUTC]. + */ + fun clock(clock: Clock) = apply { clientOptions.clock(clock) } + + /** + * The base URL to use for every request. + * + * Defaults to the production environment: `http://localhost:3000/v1`. + * + * The following other environments, with dedicated builder methods, are available: + * - environment_1: `https://api.stagehand.browserbase.com/v1` + */ + fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } + + /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ + fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) + + /** Sets [baseUrl] to `https://api.stagehand.browserbase.com/v1`. */ + fun environment1() = apply { clientOptions.environment1() } + + /** + * Whether to call `validate` on every response before returning it. + * + * Defaults to false, which means the shape of the response will not be validated upfront. + * Instead, validation will only occur for the parts of the response that are accessed. + */ + fun responseValidation(responseValidation: Boolean) = apply { + clientOptions.responseValidation(responseValidation) + } + + /** + * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding + * retries. + * + * Defaults to [Timeout.default]. + */ + fun timeout(timeout: Timeout) = apply { clientOptions.timeout(timeout) } + + /** + * Sets the maximum time allowed for a complete HTTP call, not including retries. + * + * See [Timeout.request] for more details. + * + * For fine-grained control, pass a [Timeout] object. + */ + fun timeout(timeout: Duration) = apply { clientOptions.timeout(timeout) } + + /** + * The maximum number of times to retry failed requests, with a short exponential backoff + * between requests. + * + * Only the following error types are retried: + * - Connection errors (for example, due to a network connectivity problem) + * - 408 Request Timeout + * - 409 Conflict + * - 429 Rate Limit + * - 5xx Internal + * + * The API may also explicitly instruct the SDK to retry or not retry a request. + * + * Defaults to 2. + */ + fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + + fun apiKey(apiKey: String?) = apply { clientOptions.apiKey(apiKey) } + + /** Alias for calling [Builder.apiKey] with `apiKey.orElse(null)`. */ + fun apiKey(apiKey: Optional) = apiKey(apiKey.getOrNull()) + + fun headers(headers: Headers) = apply { clientOptions.headers(headers) } + + fun headers(headers: Map>) = apply { + clientOptions.headers(headers) + } + + fun putHeader(name: String, value: String) = apply { clientOptions.putHeader(name, value) } + + fun putHeaders(name: String, values: Iterable) = apply { + clientOptions.putHeaders(name, values) + } + + fun putAllHeaders(headers: Headers) = apply { clientOptions.putAllHeaders(headers) } + + fun putAllHeaders(headers: Map>) = apply { + clientOptions.putAllHeaders(headers) + } + + fun replaceHeaders(name: String, value: String) = apply { + clientOptions.replaceHeaders(name, value) + } + + fun replaceHeaders(name: String, values: Iterable) = apply { + clientOptions.replaceHeaders(name, values) + } + + fun replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + clientOptions.replaceAllHeaders(headers) + } + + fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) } + + fun removeAllHeaders(names: Set) = apply { clientOptions.removeAllHeaders(names) } + + fun queryParams(queryParams: QueryParams) = apply { clientOptions.queryParams(queryParams) } + + fun queryParams(queryParams: Map>) = apply { + clientOptions.queryParams(queryParams) + } + + fun putQueryParam(key: String, value: String) = apply { + clientOptions.putQueryParam(key, value) + } + + fun putQueryParams(key: String, values: Iterable) = apply { + clientOptions.putQueryParams(key, values) + } + + fun putAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun putAllQueryParams(queryParams: Map>) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun replaceQueryParams(key: String, value: String) = apply { + clientOptions.replaceQueryParams(key, value) + } + + fun replaceQueryParams(key: String, values: Iterable) = apply { + clientOptions.replaceQueryParams(key, values) + } + + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun replaceAllQueryParams(queryParams: Map>) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun removeQueryParams(key: String) = apply { clientOptions.removeQueryParams(key) } + + fun removeAllQueryParams(keys: Set) = apply { + clientOptions.removeAllQueryParams(keys) + } + + /** + * Updates configuration using system properties and environment variables. + * + * @see ClientOptions.Builder.fromEnv + */ + fun fromEnv() = apply { clientOptions.fromEnv() } + + /** + * Returns an immutable instance of [StagehandClient]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): StagehandClient = + StagehandClientImpl( + clientOptions + .httpClient( + OkHttpClient.builder() + .timeout(clientOptions.timeout()) + .proxy(proxy) + .sslSocketFactory(sslSocketFactory) + .trustManager(trustManager) + .hostnameVerifier(hostnameVerifier) + .build() + ) + .build() + ) + } +} diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt new file mode 100644 index 0000000..e7a4c24 --- /dev/null +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -0,0 +1,316 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.client.okhttp + +import com.fasterxml.jackson.databind.json.JsonMapper +import com.stagehand.api.client.StagehandClientAsync +import com.stagehand.api.client.StagehandClientAsyncImpl +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.Sleeper +import com.stagehand.api.core.Timeout +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.HttpClient +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.core.jsonMapper +import java.net.Proxy +import java.time.Clock +import java.time.Duration +import java.util.Optional +import javax.net.ssl.HostnameVerifier +import javax.net.ssl.SSLSocketFactory +import javax.net.ssl.X509TrustManager +import kotlin.jvm.optionals.getOrNull + +/** + * A class that allows building an instance of [StagehandClientAsync] with [OkHttpClient] as the + * underlying [HttpClient]. + */ +class StagehandOkHttpClientAsync private constructor() { + + companion object { + + /** Returns a mutable builder for constructing an instance of [StagehandClientAsync]. */ + @JvmStatic fun builder() = Builder() + + /** + * Returns a client configured using system properties and environment variables. + * + * @see ClientOptions.Builder.fromEnv + */ + @JvmStatic fun fromEnv(): StagehandClientAsync = builder().fromEnv().build() + } + + /** A builder for [StagehandOkHttpClientAsync]. */ + class Builder internal constructor() { + + private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var proxy: Proxy? = null + private var sslSocketFactory: SSLSocketFactory? = null + private var trustManager: X509TrustManager? = null + private var hostnameVerifier: HostnameVerifier? = null + + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + + /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ + fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + + /** + * The socket factory used to secure HTTPS connections. + * + * If this is set, then [trustManager] must also be set. + * + * If unset, then the system default is used. Most applications should not call this method, + * and instead use the system default. The default include special optimizations that can be + * lost if the implementation is modified. + */ + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { + this.sslSocketFactory = sslSocketFactory + } + + /** Alias for calling [Builder.sslSocketFactory] with `sslSocketFactory.orElse(null)`. */ + fun sslSocketFactory(sslSocketFactory: Optional) = + sslSocketFactory(sslSocketFactory.getOrNull()) + + /** + * The trust manager used to secure HTTPS connections. + * + * If this is set, then [sslSocketFactory] must also be set. + * + * If unset, then the system default is used. Most applications should not call this method, + * and instead use the system default. The default include special optimizations that can be + * lost if the implementation is modified. + */ + fun trustManager(trustManager: X509TrustManager?) = apply { + this.trustManager = trustManager + } + + /** Alias for calling [Builder.trustManager] with `trustManager.orElse(null)`. */ + fun trustManager(trustManager: Optional) = + trustManager(trustManager.getOrNull()) + + /** + * The verifier used to confirm that response certificates apply to requested hostnames for + * HTTPS connections. + * + * If unset, then a default hostname verifier is used. + */ + fun hostnameVerifier(hostnameVerifier: HostnameVerifier?) = apply { + this.hostnameVerifier = hostnameVerifier + } + + /** Alias for calling [Builder.hostnameVerifier] with `hostnameVerifier.orElse(null)`. */ + fun hostnameVerifier(hostnameVerifier: Optional) = + hostnameVerifier(hostnameVerifier.getOrNull()) + + /** + * Whether to throw an exception if any of the Jackson versions detected at runtime are + * incompatible with the SDK's minimum supported Jackson version (2.13.4). + * + * Defaults to true. Use extreme caution when disabling this option. There is no guarantee + * that the SDK will work correctly when using an incompatible Jackson version. + */ + fun checkJacksonVersionCompatibility(checkJacksonVersionCompatibility: Boolean) = apply { + clientOptions.checkJacksonVersionCompatibility(checkJacksonVersionCompatibility) + } + + /** + * The Jackson JSON mapper to use for serializing and deserializing JSON. + * + * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and + * rarely needs to be overridden. + */ + fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } + + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + fun sleeper(sleeper: Sleeper) = apply { clientOptions.sleeper(sleeper) } + + /** + * The clock to use for operations that require timing, like retries. + * + * This is primarily useful for using a fake clock in tests. + * + * Defaults to [Clock.systemUTC]. + */ + fun clock(clock: Clock) = apply { clientOptions.clock(clock) } + + /** + * The base URL to use for every request. + * + * Defaults to the production environment: `http://localhost:3000/v1`. + * + * The following other environments, with dedicated builder methods, are available: + * - environment_1: `https://api.stagehand.browserbase.com/v1` + */ + fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } + + /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ + fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) + + /** Sets [baseUrl] to `https://api.stagehand.browserbase.com/v1`. */ + fun environment1() = apply { clientOptions.environment1() } + + /** + * Whether to call `validate` on every response before returning it. + * + * Defaults to false, which means the shape of the response will not be validated upfront. + * Instead, validation will only occur for the parts of the response that are accessed. + */ + fun responseValidation(responseValidation: Boolean) = apply { + clientOptions.responseValidation(responseValidation) + } + + /** + * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding + * retries. + * + * Defaults to [Timeout.default]. + */ + fun timeout(timeout: Timeout) = apply { clientOptions.timeout(timeout) } + + /** + * Sets the maximum time allowed for a complete HTTP call, not including retries. + * + * See [Timeout.request] for more details. + * + * For fine-grained control, pass a [Timeout] object. + */ + fun timeout(timeout: Duration) = apply { clientOptions.timeout(timeout) } + + /** + * The maximum number of times to retry failed requests, with a short exponential backoff + * between requests. + * + * Only the following error types are retried: + * - Connection errors (for example, due to a network connectivity problem) + * - 408 Request Timeout + * - 409 Conflict + * - 429 Rate Limit + * - 5xx Internal + * + * The API may also explicitly instruct the SDK to retry or not retry a request. + * + * Defaults to 2. + */ + fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + + fun apiKey(apiKey: String?) = apply { clientOptions.apiKey(apiKey) } + + /** Alias for calling [Builder.apiKey] with `apiKey.orElse(null)`. */ + fun apiKey(apiKey: Optional) = apiKey(apiKey.getOrNull()) + + fun headers(headers: Headers) = apply { clientOptions.headers(headers) } + + fun headers(headers: Map>) = apply { + clientOptions.headers(headers) + } + + fun putHeader(name: String, value: String) = apply { clientOptions.putHeader(name, value) } + + fun putHeaders(name: String, values: Iterable) = apply { + clientOptions.putHeaders(name, values) + } + + fun putAllHeaders(headers: Headers) = apply { clientOptions.putAllHeaders(headers) } + + fun putAllHeaders(headers: Map>) = apply { + clientOptions.putAllHeaders(headers) + } + + fun replaceHeaders(name: String, value: String) = apply { + clientOptions.replaceHeaders(name, value) + } + + fun replaceHeaders(name: String, values: Iterable) = apply { + clientOptions.replaceHeaders(name, values) + } + + fun replaceAllHeaders(headers: Headers) = apply { clientOptions.replaceAllHeaders(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + clientOptions.replaceAllHeaders(headers) + } + + fun removeHeaders(name: String) = apply { clientOptions.removeHeaders(name) } + + fun removeAllHeaders(names: Set) = apply { clientOptions.removeAllHeaders(names) } + + fun queryParams(queryParams: QueryParams) = apply { clientOptions.queryParams(queryParams) } + + fun queryParams(queryParams: Map>) = apply { + clientOptions.queryParams(queryParams) + } + + fun putQueryParam(key: String, value: String) = apply { + clientOptions.putQueryParam(key, value) + } + + fun putQueryParams(key: String, values: Iterable) = apply { + clientOptions.putQueryParams(key, values) + } + + fun putAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun putAllQueryParams(queryParams: Map>) = apply { + clientOptions.putAllQueryParams(queryParams) + } + + fun replaceQueryParams(key: String, value: String) = apply { + clientOptions.replaceQueryParams(key, value) + } + + fun replaceQueryParams(key: String, values: Iterable) = apply { + clientOptions.replaceQueryParams(key, values) + } + + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun replaceAllQueryParams(queryParams: Map>) = apply { + clientOptions.replaceAllQueryParams(queryParams) + } + + fun removeQueryParams(key: String) = apply { clientOptions.removeQueryParams(key) } + + fun removeAllQueryParams(keys: Set) = apply { + clientOptions.removeAllQueryParams(keys) + } + + /** + * Updates configuration using system properties and environment variables. + * + * @see ClientOptions.Builder.fromEnv + */ + fun fromEnv() = apply { clientOptions.fromEnv() } + + /** + * Returns an immutable instance of [StagehandClientAsync]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): StagehandClientAsync = + StagehandClientAsyncImpl( + clientOptions + .httpClient( + OkHttpClient.builder() + .timeout(clientOptions.timeout()) + .proxy(proxy) + .sslSocketFactory(sslSocketFactory) + .trustManager(trustManager) + .hostnameVerifier(hostnameVerifier) + .build() + ) + .build() + ) + } +} diff --git a/stagehand-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt b/stagehand-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt new file mode 100644 index 0000000..950e323 --- /dev/null +++ b/stagehand-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt @@ -0,0 +1,44 @@ +package com.stagehand.api.client.okhttp + +import com.github.tomakehurst.wiremock.client.WireMock.* +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import com.stagehand.api.core.http.HttpMethod +import com.stagehand.api.core.http.HttpRequest +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.ResourceLock + +@WireMockTest +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class OkHttpClientTest { + + private lateinit var baseUrl: String + private lateinit var httpClient: OkHttpClient + + @BeforeEach + fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { + baseUrl = wmRuntimeInfo.httpBaseUrl + httpClient = OkHttpClient.builder().build() + } + + @Test + fun executeAsync_whenFutureCancelled_cancelsUnderlyingCall() { + stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) + val responseFuture = + httpClient.executeAsync( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build() + ) + val call = httpClient.okHttpClient.dispatcher.runningCalls().single() + + responseFuture.cancel(false) + + // Should have cancelled the underlying call + assertThat(call.isCanceled()).isTrue() + } +} diff --git a/stagehand-java-core/build.gradle.kts b/stagehand-java-core/build.gradle.kts new file mode 100644 index 0000000..38bcf47 --- /dev/null +++ b/stagehand-java-core/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + id("stagehand.kotlin") + id("stagehand.publish") +} + +configurations.all { + resolutionStrategy { + // Compile and test against a lower Jackson version to ensure we're compatible with it. + // We publish with a higher version (see below) to ensure users depend on a secure version by default. + force("com.fasterxml.jackson.core:jackson-core:2.13.4") + force("com.fasterxml.jackson.core:jackson-databind:2.13.4") + force("com.fasterxml.jackson.core:jackson-annotations:2.13.4") + force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4") + force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4") + force("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + } +} + +dependencies { + api("com.fasterxml.jackson.core:jackson-core:2.18.2") + api("com.fasterxml.jackson.core:jackson-databind:2.18.2") + api("com.google.errorprone:error_prone_annotations:2.33.0") + + implementation("com.fasterxml.jackson.core:jackson-annotations:2.18.2") + implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2") + implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.2") + implementation("org.apache.httpcomponents.core5:httpcore5:5.2.4") + implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") + + testImplementation(kotlin("test")) + testImplementation(project(":stagehand-java-client-okhttp")) + testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") + testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") + testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.3") + testImplementation("org.junit-pioneer:junit-pioneer:1.9.1") + testImplementation("org.mockito:mockito-core:5.14.2") + testImplementation("org.mockito:mockito-junit-jupiter:5.14.2") + testImplementation("org.mockito.kotlin:mockito-kotlin:4.1.0") +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt new file mode 100644 index 0000000..bd37148 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt @@ -0,0 +1,72 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.client + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.services.blocking.SessionService +import java.util.function.Consumer + +/** + * A client for interacting with the Stagehand REST API synchronously. You can also switch to + * asynchronous execution via the [async] method. + * + * This client performs best when you create a single instance and reuse it for all interactions + * with the REST API. This is because each client holds its own connection pool and thread pools. + * Reusing connections and threads reduces latency and saves memory. The client also handles rate + * limiting per client. This means that creating and using multiple instances at the same time will + * not respect rate limits. + * + * The threads and connections that are held will be released automatically if they remain idle. But + * if you are writing an application that needs to aggressively release unused resources, then you + * may call [close]. + */ +interface StagehandClient { + + /** + * Returns a version of this client that uses asynchronous execution. + * + * The returned client shares its resources, like its connection pool and thread pools, with + * this client. + */ + fun async(): StagehandClientAsync + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): StagehandClient + + fun sessions(): SessionService + + /** + * Closes this client, relinquishing any underlying resources. + * + * This is purposefully not inherited from [AutoCloseable] because the client is long-lived and + * usually should not be synchronously closed via try-with-resources. + * + * It's also usually not necessary to call this method at all. the default HTTP client + * automatically releases threads and connections if they remain idle, but if you are writing an + * application that needs to aggressively release unused resources, then you may call this + * method. + */ + fun close() + + /** A view of [StagehandClient] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): StagehandClient.WithRawResponse + + fun sessions(): SessionService.WithRawResponse + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt new file mode 100644 index 0000000..078550d --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt @@ -0,0 +1,76 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.client + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.services.async.SessionServiceAsync +import java.util.function.Consumer + +/** + * A client for interacting with the Stagehand REST API asynchronously. You can also switch to + * synchronous execution via the [sync] method. + * + * This client performs best when you create a single instance and reuse it for all interactions + * with the REST API. This is because each client holds its own connection pool and thread pools. + * Reusing connections and threads reduces latency and saves memory. The client also handles rate + * limiting per client. This means that creating and using multiple instances at the same time will + * not respect rate limits. + * + * The threads and connections that are held will be released automatically if they remain idle. But + * if you are writing an application that needs to aggressively release unused resources, then you + * may call [close]. + */ +interface StagehandClientAsync { + + /** + * Returns a version of this client that uses synchronous execution. + * + * The returned client shares its resources, like its connection pool and thread pools, with + * this client. + */ + fun sync(): StagehandClient + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): StagehandClientAsync + + fun sessions(): SessionServiceAsync + + /** + * Closes this client, relinquishing any underlying resources. + * + * This is purposefully not inherited from [AutoCloseable] because the client is long-lived and + * usually should not be synchronously closed via try-with-resources. + * + * It's also usually not necessary to call this method at all. the default HTTP client + * automatically releases threads and connections if they remain idle, but if you are writing an + * application that needs to aggressively release unused resources, then you may call this + * method. + */ + fun close() + + /** + * A view of [StagehandClientAsync] that provides access to raw HTTP responses for each method. + */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions( + modifier: Consumer + ): StagehandClientAsync.WithRawResponse + + fun sessions(): SessionServiceAsync.WithRawResponse + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt new file mode 100644 index 0000000..60cbec7 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt @@ -0,0 +1,59 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.client + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.getPackageVersion +import com.stagehand.api.services.async.SessionServiceAsync +import com.stagehand.api.services.async.SessionServiceAsyncImpl +import java.util.function.Consumer + +class StagehandClientAsyncImpl(private val clientOptions: ClientOptions) : StagehandClientAsync { + + private val clientOptionsWithUserAgent = + if (clientOptions.headers.names().contains("User-Agent")) clientOptions + else + clientOptions + .toBuilder() + .putHeader("User-Agent", "${javaClass.simpleName}/Java ${getPackageVersion()}") + .build() + + // Pass the original clientOptions so that this client sets its own User-Agent. + private val sync: StagehandClient by lazy { StagehandClientImpl(clientOptions) } + + private val withRawResponse: StagehandClientAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val sessions: SessionServiceAsync by lazy { + SessionServiceAsyncImpl(clientOptionsWithUserAgent) + } + + override fun sync(): StagehandClient = sync + + override fun withRawResponse(): StagehandClientAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: Consumer): StagehandClientAsync = + StagehandClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + + override fun sessions(): SessionServiceAsync = sessions + + override fun close() = clientOptions.close() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + StagehandClientAsync.WithRawResponse { + + private val sessions: SessionServiceAsync.WithRawResponse by lazy { + SessionServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: Consumer + ): StagehandClientAsync.WithRawResponse = + StagehandClientAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + override fun sessions(): SessionServiceAsync.WithRawResponse = sessions + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt new file mode 100644 index 0000000..39ff1e2 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt @@ -0,0 +1,57 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.client + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.getPackageVersion +import com.stagehand.api.services.blocking.SessionService +import com.stagehand.api.services.blocking.SessionServiceImpl +import java.util.function.Consumer + +class StagehandClientImpl(private val clientOptions: ClientOptions) : StagehandClient { + + private val clientOptionsWithUserAgent = + if (clientOptions.headers.names().contains("User-Agent")) clientOptions + else + clientOptions + .toBuilder() + .putHeader("User-Agent", "${javaClass.simpleName}/Java ${getPackageVersion()}") + .build() + + // Pass the original clientOptions so that this client sets its own User-Agent. + private val async: StagehandClientAsync by lazy { StagehandClientAsyncImpl(clientOptions) } + + private val withRawResponse: StagehandClient.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val sessions: SessionService by lazy { SessionServiceImpl(clientOptionsWithUserAgent) } + + override fun async(): StagehandClientAsync = async + + override fun withRawResponse(): StagehandClient.WithRawResponse = withRawResponse + + override fun withOptions(modifier: Consumer): StagehandClient = + StagehandClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + + override fun sessions(): SessionService = sessions + + override fun close() = clientOptions.close() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + StagehandClient.WithRawResponse { + + private val sessions: SessionService.WithRawResponse by lazy { + SessionServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun withOptions( + modifier: Consumer + ): StagehandClient.WithRawResponse = + StagehandClientImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + override fun sessions(): SessionService.WithRawResponse = sessions + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt new file mode 100644 index 0000000..98c91bd --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt @@ -0,0 +1,44 @@ +package com.stagehand.api.core + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.BeanProperty +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JavaType +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.deser.ContextualDeserializer +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import kotlin.reflect.KClass + +abstract class BaseDeserializer(type: KClass) : + StdDeserializer(type.java), ContextualDeserializer { + + override fun createContextual( + context: DeserializationContext, + property: BeanProperty?, + ): JsonDeserializer { + return this + } + + override fun deserialize(parser: JsonParser, context: DeserializationContext): T { + return parser.codec.deserialize(parser.readValueAsTree()) + } + + protected abstract fun ObjectCodec.deserialize(node: JsonNode): T + + protected fun ObjectCodec.tryDeserialize(node: JsonNode, type: TypeReference): T? = + try { + readValue(treeAsTokens(node), type) + } catch (e: Exception) { + null + } + + protected fun ObjectCodec.tryDeserialize(node: JsonNode, type: JavaType): T? = + try { + readValue(treeAsTokens(node), type) + } catch (e: Exception) { + null + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt new file mode 100644 index 0000000..929a990 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt @@ -0,0 +1,6 @@ +package com.stagehand.api.core + +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import kotlin.reflect.KClass + +abstract class BaseSerializer(type: KClass) : StdSerializer(type.java) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt new file mode 100644 index 0000000..e61fae8 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt @@ -0,0 +1,96 @@ +@file:JvmName("Check") + +package com.stagehand.api.core + +import com.fasterxml.jackson.core.Version +import com.fasterxml.jackson.core.util.VersionUtil + +fun checkRequired(name: String, condition: Boolean) = + check(condition) { "`$name` is required, but was not set" } + +fun checkRequired(name: String, value: T?): T = + checkNotNull(value) { "`$name` is required, but was not set" } + +@JvmSynthetic +internal fun checkKnown(name: String, value: JsonField): T = + value.asKnown().orElseThrow { + IllegalStateException("`$name` is not a known type: ${value.javaClass.simpleName}") + } + +@JvmSynthetic +internal fun checkKnown(name: String, value: MultipartField): T = + value.value.asKnown().orElseThrow { + IllegalStateException("`$name` is not a known type: ${value.javaClass.simpleName}") + } + +@JvmSynthetic +internal fun checkLength(name: String, value: String, length: Int): String = + value.also { + check(it.length == length) { "`$name` must have length $length, but was ${it.length}" } + } + +@JvmSynthetic +internal fun checkMinLength(name: String, value: String, minLength: Int): String = + value.also { + check(it.length >= minLength) { + if (minLength == 1) "`$name` must be non-empty, but was empty" + else "`$name` must have at least length $minLength, but was ${it.length}" + } + } + +@JvmSynthetic +internal fun checkMaxLength(name: String, value: String, maxLength: Int): String = + value.also { + check(it.length <= maxLength) { + "`$name` must have at most length $maxLength, but was ${it.length}" + } + } + +@JvmSynthetic +internal fun checkJacksonVersionCompatibility() { + val incompatibleJacksonVersions = + RUNTIME_JACKSON_VERSIONS.mapNotNull { + val badVersionReason = BAD_JACKSON_VERSIONS[it.toString()] + when { + it.majorVersion != MINIMUM_JACKSON_VERSION.majorVersion -> + it to "incompatible major version" + it.minorVersion < MINIMUM_JACKSON_VERSION.minorVersion -> + it to "minor version too low" + it.minorVersion == MINIMUM_JACKSON_VERSION.minorVersion && + it.patchLevel < MINIMUM_JACKSON_VERSION.patchLevel -> + it to "patch version too low" + badVersionReason != null -> it to badVersionReason + else -> null + } + } + check(incompatibleJacksonVersions.isEmpty()) { + """ +This SDK requires a minimum Jackson version of $MINIMUM_JACKSON_VERSION, but the following incompatible Jackson versions were detected at runtime: + +${incompatibleJacksonVersions.asSequence().map { (version, incompatibilityReason) -> + "- `${version.toFullString().replace("/", ":")}` ($incompatibilityReason)" +}.joinToString("\n")} + +This can happen if you are either: +1. Directly depending on different Jackson versions +2. Depending on some library that depends on different Jackson versions, potentially transitively + +Double-check that you are depending on compatible Jackson versions. + +See https://www.github.com/stainless-sdks/stagehand-java#jackson for more information. + """ + .trimIndent() + } +} + +private val MINIMUM_JACKSON_VERSION: Version = VersionUtil.parseVersion("2.13.4", null, null) +private val BAD_JACKSON_VERSIONS: Map = + mapOf("2.18.1" to "due to https://github.com/FasterXML/jackson-databind/issues/4639") +private val RUNTIME_JACKSON_VERSIONS: List = + listOf( + com.fasterxml.jackson.core.json.PackageVersion.VERSION, + com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION, + com.fasterxml.jackson.datatype.jdk8.PackageVersion.VERSION, + com.fasterxml.jackson.datatype.jsr310.PackageVersion.VERSION, + com.fasterxml.jackson.module.kotlin.PackageVersion.VERSION, + ) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt new file mode 100644 index 0000000..50b2df9 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt @@ -0,0 +1,463 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.core + +import com.fasterxml.jackson.databind.json.JsonMapper +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.HttpClient +import com.stagehand.api.core.http.PhantomReachableClosingHttpClient +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.core.http.RetryingHttpClient +import java.time.Clock +import java.time.Duration +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** A class representing the SDK client configuration. */ +class ClientOptions +private constructor( + private val originalHttpClient: HttpClient, + /** + * The HTTP client to use in the SDK. + * + * Use the one published in `stagehand-java-client-okhttp` or implement your own. + * + * This class takes ownership of the client and closes it when closed. + */ + @get:JvmName("httpClient") val httpClient: HttpClient, + /** + * Whether to throw an exception if any of the Jackson versions detected at runtime are + * incompatible with the SDK's minimum supported Jackson version (2.13.4). + * + * Defaults to true. Use extreme caution when disabling this option. There is no guarantee that + * the SDK will work correctly when using an incompatible Jackson version. + */ + @get:JvmName("checkJacksonVersionCompatibility") val checkJacksonVersionCompatibility: Boolean, + /** + * The Jackson JSON mapper to use for serializing and deserializing JSON. + * + * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and rarely + * needs to be overridden. + */ + @get:JvmName("jsonMapper") val jsonMapper: JsonMapper, + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + @get:JvmName("sleeper") val sleeper: Sleeper, + /** + * The clock to use for operations that require timing, like retries. + * + * This is primarily useful for using a fake clock in tests. + * + * Defaults to [Clock.systemUTC]. + */ + @get:JvmName("clock") val clock: Clock, + private val baseUrl: String?, + /** Headers to send with the request. */ + @get:JvmName("headers") val headers: Headers, + /** Query params to send with the request. */ + @get:JvmName("queryParams") val queryParams: QueryParams, + /** + * Whether to call `validate` on every response before returning it. + * + * Defaults to false, which means the shape of the response will not be validated upfront. + * Instead, validation will only occur for the parts of the response that are accessed. + */ + @get:JvmName("responseValidation") val responseValidation: Boolean, + /** + * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding + * retries. + * + * Defaults to [Timeout.default]. + */ + @get:JvmName("timeout") val timeout: Timeout, + /** + * The maximum number of times to retry failed requests, with a short exponential backoff + * between requests. + * + * Only the following error types are retried: + * - Connection errors (for example, due to a network connectivity problem) + * - 408 Request Timeout + * - 409 Conflict + * - 429 Rate Limit + * - 5xx Internal + * + * The API may also explicitly instruct the SDK to retry or not retry a request. + * + * Defaults to 2. + */ + @get:JvmName("maxRetries") val maxRetries: Int, + private val apiKey: String?, +) { + + init { + if (checkJacksonVersionCompatibility) { + checkJacksonVersionCompatibility() + } + } + + /** + * The base URL to use for every request. + * + * Defaults to the production environment: `http://localhost:3000/v1`. + * + * The following other environments, with dedicated builder methods, are available: + * - environment_1: `https://api.stagehand.browserbase.com/v1` + */ + fun baseUrl(): String = baseUrl ?: PRODUCTION_URL + + fun apiKey(): Optional = Optional.ofNullable(apiKey) + + fun toBuilder() = Builder().from(this) + + companion object { + + const val PRODUCTION_URL = "http://localhost:3000/v1" + + const val ENVIRONMENT_1_URL = "https://api.stagehand.browserbase.com/v1" + + /** + * Returns a mutable builder for constructing an instance of [ClientOptions]. + * + * The following fields are required: + * ```java + * .httpClient() + * ``` + */ + @JvmStatic fun builder() = Builder() + + /** + * Returns options configured using system properties and environment variables. + * + * @see Builder.fromEnv + */ + @JvmStatic fun fromEnv(): ClientOptions = builder().fromEnv().build() + } + + /** A builder for [ClientOptions]. */ + class Builder internal constructor() { + + private var httpClient: HttpClient? = null + private var checkJacksonVersionCompatibility: Boolean = true + private var jsonMapper: JsonMapper = jsonMapper() + private var sleeper: Sleeper? = null + private var clock: Clock = Clock.systemUTC() + private var baseUrl: String? = null + private var headers: Headers.Builder = Headers.builder() + private var queryParams: QueryParams.Builder = QueryParams.builder() + private var responseValidation: Boolean = false + private var timeout: Timeout = Timeout.default() + private var maxRetries: Int = 2 + private var apiKey: String? = null + + @JvmSynthetic + internal fun from(clientOptions: ClientOptions) = apply { + httpClient = clientOptions.originalHttpClient + checkJacksonVersionCompatibility = clientOptions.checkJacksonVersionCompatibility + jsonMapper = clientOptions.jsonMapper + sleeper = clientOptions.sleeper + clock = clientOptions.clock + baseUrl = clientOptions.baseUrl + headers = clientOptions.headers.toBuilder() + queryParams = clientOptions.queryParams.toBuilder() + responseValidation = clientOptions.responseValidation + timeout = clientOptions.timeout + maxRetries = clientOptions.maxRetries + apiKey = clientOptions.apiKey + } + + /** + * The HTTP client to use in the SDK. + * + * Use the one published in `stagehand-java-client-okhttp` or implement your own. + * + * This class takes ownership of the client and closes it when closed. + */ + fun httpClient(httpClient: HttpClient) = apply { + this.httpClient = PhantomReachableClosingHttpClient(httpClient) + } + + /** + * Whether to throw an exception if any of the Jackson versions detected at runtime are + * incompatible with the SDK's minimum supported Jackson version (2.13.4). + * + * Defaults to true. Use extreme caution when disabling this option. There is no guarantee + * that the SDK will work correctly when using an incompatible Jackson version. + */ + fun checkJacksonVersionCompatibility(checkJacksonVersionCompatibility: Boolean) = apply { + this.checkJacksonVersionCompatibility = checkJacksonVersionCompatibility + } + + /** + * The Jackson JSON mapper to use for serializing and deserializing JSON. + * + * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and + * rarely needs to be overridden. + */ + fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } + + /** + * The interface to use for delaying execution, like during retries. + * + * This is primarily useful for using fake delays in tests. + * + * Defaults to real execution delays. + * + * This class takes ownership of the sleeper and closes it when closed. + */ + fun sleeper(sleeper: Sleeper) = apply { this.sleeper = PhantomReachableSleeper(sleeper) } + + /** + * The clock to use for operations that require timing, like retries. + * + * This is primarily useful for using a fake clock in tests. + * + * Defaults to [Clock.systemUTC]. + */ + fun clock(clock: Clock) = apply { this.clock = clock } + + /** + * The base URL to use for every request. + * + * Defaults to the production environment: `http://localhost:3000/v1`. + * + * The following other environments, with dedicated builder methods, are available: + * - environment_1: `https://api.stagehand.browserbase.com/v1` + */ + fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl } + + /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ + fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) + + /** Sets [baseUrl] to `https://api.stagehand.browserbase.com/v1`. */ + fun environment1() = baseUrl(ENVIRONMENT_1_URL) + + /** + * Whether to call `validate` on every response before returning it. + * + * Defaults to false, which means the shape of the response will not be validated upfront. + * Instead, validation will only occur for the parts of the response that are accessed. + */ + fun responseValidation(responseValidation: Boolean) = apply { + this.responseValidation = responseValidation + } + + /** + * Sets the maximum time allowed for various parts of an HTTP call's lifecycle, excluding + * retries. + * + * Defaults to [Timeout.default]. + */ + fun timeout(timeout: Timeout) = apply { this.timeout = timeout } + + /** + * Sets the maximum time allowed for a complete HTTP call, not including retries. + * + * See [Timeout.request] for more details. + * + * For fine-grained control, pass a [Timeout] object. + */ + fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build()) + + /** + * The maximum number of times to retry failed requests, with a short exponential backoff + * between requests. + * + * Only the following error types are retried: + * - Connection errors (for example, due to a network connectivity problem) + * - 408 Request Timeout + * - 409 Conflict + * - 429 Rate Limit + * - 5xx Internal + * + * The API may also explicitly instruct the SDK to retry or not retry a request. + * + * Defaults to 2. + */ + fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } + + fun apiKey(apiKey: String?) = apply { this.apiKey = apiKey } + + /** Alias for calling [Builder.apiKey] with `apiKey.orElse(null)`. */ + fun apiKey(apiKey: Optional) = apiKey(apiKey.getOrNull()) + + fun headers(headers: Headers) = apply { + this.headers.clear() + putAllHeaders(headers) + } + + fun headers(headers: Map>) = apply { + this.headers.clear() + putAllHeaders(headers) + } + + fun putHeader(name: String, value: String) = apply { headers.put(name, value) } + + fun putHeaders(name: String, values: Iterable) = apply { headers.put(name, values) } + + fun putAllHeaders(headers: Headers) = apply { this.headers.putAll(headers) } + + fun putAllHeaders(headers: Map>) = apply { + this.headers.putAll(headers) + } + + fun replaceHeaders(name: String, value: String) = apply { headers.replace(name, value) } + + fun replaceHeaders(name: String, values: Iterable) = apply { + headers.replace(name, values) + } + + fun replaceAllHeaders(headers: Headers) = apply { this.headers.replaceAll(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + this.headers.replaceAll(headers) + } + + fun removeHeaders(name: String) = apply { headers.remove(name) } + + fun removeAllHeaders(names: Set) = apply { headers.removeAll(names) } + + fun queryParams(queryParams: QueryParams) = apply { + this.queryParams.clear() + putAllQueryParams(queryParams) + } + + fun queryParams(queryParams: Map>) = apply { + this.queryParams.clear() + putAllQueryParams(queryParams) + } + + fun putQueryParam(key: String, value: String) = apply { queryParams.put(key, value) } + + fun putQueryParams(key: String, values: Iterable) = apply { + queryParams.put(key, values) + } + + fun putAllQueryParams(queryParams: QueryParams) = apply { + this.queryParams.putAll(queryParams) + } + + fun putAllQueryParams(queryParams: Map>) = apply { + this.queryParams.putAll(queryParams) + } + + fun replaceQueryParams(key: String, value: String) = apply { + queryParams.replace(key, value) + } + + fun replaceQueryParams(key: String, values: Iterable) = apply { + queryParams.replace(key, values) + } + + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + this.queryParams.replaceAll(queryParams) + } + + fun replaceAllQueryParams(queryParams: Map>) = apply { + this.queryParams.replaceAll(queryParams) + } + + fun removeQueryParams(key: String) = apply { queryParams.remove(key) } + + fun removeAllQueryParams(keys: Set) = apply { queryParams.removeAll(keys) } + + fun timeout(): Timeout = timeout + + /** + * Updates configuration using system properties and environment variables. + * + * See this table for the available options: + * + * |Setter |System property |Environment variable|Required|Default value | + * |---------|-------------------|--------------------|--------|----------------------------| + * |`apiKey` |`stagehand.apiKey` |`STAGEHAND_API_KEY` |false |- | + * |`baseUrl`|`stagehand.baseUrl`|`STAGEHAND_BASE_URL`|true |`"http://localhost:3000/v1"`| + * + * System properties take precedence over environment variables. + */ + fun fromEnv() = apply { + (System.getProperty("stagehand.baseUrl") ?: System.getenv("STAGEHAND_BASE_URL"))?.let { + baseUrl(it) + } + (System.getProperty("stagehand.apiKey") ?: System.getenv("STAGEHAND_API_KEY"))?.let { + apiKey(it) + } + } + + /** + * Returns an immutable instance of [ClientOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .httpClient() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ClientOptions { + val httpClient = checkRequired("httpClient", httpClient) + val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) + + val headers = Headers.builder() + val queryParams = QueryParams.builder() + headers.put("X-Stainless-Lang", "java") + headers.put("X-Stainless-Arch", getOsArch()) + headers.put("X-Stainless-OS", getOsName()) + headers.put("X-Stainless-OS-Version", getOsVersion()) + headers.put("X-Stainless-Package-Version", getPackageVersion()) + headers.put("X-Stainless-Runtime", "JRE") + headers.put("X-Stainless-Runtime-Version", getJavaVersion()) + apiKey?.let { + if (!it.isEmpty()) { + headers.put("Authorization", "Bearer $it") + } + } + headers.replaceAll(this.headers.build()) + queryParams.replaceAll(this.queryParams.build()) + + return ClientOptions( + httpClient, + RetryingHttpClient.builder() + .httpClient(httpClient) + .sleeper(sleeper) + .clock(clock) + .maxRetries(maxRetries) + .build(), + checkJacksonVersionCompatibility, + jsonMapper, + sleeper, + clock, + baseUrl, + headers.build(), + queryParams.build(), + responseValidation, + timeout, + maxRetries, + apiKey, + ) + } + } + + /** + * Closes these client options, relinquishing any underlying resources. + * + * This is purposefully not inherited from [AutoCloseable] because the client options are + * long-lived and usually should not be synchronously closed via try-with-resources. + * + * It's also usually not necessary to call this method at all. the default client automatically + * releases threads and connections if they remain idle, but if you are writing an application + * that needs to aggressively release unused resources, then you may call this method. + */ + fun close() { + httpClient.close() + sleeper.close() + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt new file mode 100644 index 0000000..039a60c --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt @@ -0,0 +1,28 @@ +package com.stagehand.api.core + +import java.time.Duration +import java.util.Timer +import java.util.TimerTask +import java.util.concurrent.CompletableFuture + +class DefaultSleeper : Sleeper { + + private val timer = Timer("DefaultSleeper", true) + + override fun sleep(duration: Duration) = Thread.sleep(duration.toMillis()) + + override fun sleepAsync(duration: Duration): CompletableFuture { + val future = CompletableFuture() + timer.schedule( + object : TimerTask() { + override fun run() { + future.complete(null) + } + }, + duration.toMillis(), + ) + return future + } + + override fun close() = timer.cancel() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt new file mode 100644 index 0000000..29d99af --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt @@ -0,0 +1,167 @@ +@file:JvmName("ObjectMappers") + +package com.stagehand.api.core + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParseException +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.MapperFeature +import com.fasterxml.jackson.databind.SerializationFeature +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.cfg.CoercionAction +import com.fasterxml.jackson.databind.cfg.CoercionInputShape +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.type.LogicalType +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.kotlinModule +import java.io.InputStream +import java.time.DateTimeException +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoField + +fun jsonMapper(): JsonMapper = + JsonMapper.builder() + .addModule(kotlinModule()) + .addModule(Jdk8Module()) + .addModule(JavaTimeModule()) + .addModule( + SimpleModule() + .addSerializer(InputStreamSerializer) + .addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer()) + ) + .withCoercionConfig(LogicalType.Boolean) { + it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.Integer) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.Float) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.Textual) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.Array) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.Collection) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.Map) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } + .withCoercionConfig(LogicalType.POJO) { + it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.String, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + } + .serializationInclusion(JsonInclude.Include.NON_ABSENT) + .disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE) + .disable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS) + .disable(MapperFeature.ALLOW_COERCION_OF_SCALARS) + .disable(MapperFeature.AUTO_DETECT_CREATORS) + .disable(MapperFeature.AUTO_DETECT_FIELDS) + .disable(MapperFeature.AUTO_DETECT_GETTERS) + .disable(MapperFeature.AUTO_DETECT_IS_GETTERS) + .disable(MapperFeature.AUTO_DETECT_SETTERS) + .build() + +/** A serializer that serializes [InputStream] to bytes. */ +private object InputStreamSerializer : BaseSerializer(InputStream::class) { + + private fun readResolve(): Any = InputStreamSerializer + + override fun serialize( + value: InputStream?, + gen: JsonGenerator?, + serializers: SerializerProvider?, + ) { + if (value == null) { + gen?.writeNull() + } else { + value.use { gen?.writeBinary(it.readBytes()) } + } + } +} + +/** + * A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes. + */ +private class LenientLocalDateTimeDeserializer : + StdDeserializer(LocalDateTime::class.java) { + + companion object { + + private val DATE_TIME_FORMATTERS = + listOf( + DateTimeFormatter.ISO_LOCAL_DATE_TIME, + DateTimeFormatter.ISO_LOCAL_DATE, + DateTimeFormatter.ISO_ZONED_DATE_TIME, + ) + } + + override fun logicalType(): LogicalType = LogicalType.DateTime + + override fun deserialize(p: JsonParser, context: DeserializationContext?): LocalDateTime { + val exceptions = mutableListOf() + + for (formatter in DATE_TIME_FORMATTERS) { + try { + val temporal = formatter.parse(p.text) + + return when { + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal).atStartOfDay() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal) + else -> ZonedDateTime.from(temporal).toLocalDateTime() + } + } catch (e: DateTimeException) { + exceptions.add(e) + } + } + + throw JsonParseException(p, "Cannot parse `LocalDateTime` from value: ${p.text}").apply { + exceptions.forEach { addSuppressed(it) } + } + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt new file mode 100644 index 0000000..7f5a2f1 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt @@ -0,0 +1,16 @@ +package com.stagehand.api.core + +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams + +/** An interface representing parameters passed to a service method. */ +interface Params { + /** The full set of headers in the parameters, including both fixed and additional headers. */ + fun _headers(): Headers + + /** + * The full set of query params in the parameters, including both fixed and additional query + * params. + */ + fun _queryParams(): QueryParams +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt new file mode 100644 index 0000000..48c4eb3 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt @@ -0,0 +1,56 @@ +@file:JvmName("PhantomReachable") + +package com.stagehand.api.core + +import com.stagehand.api.errors.StagehandException +import java.lang.reflect.InvocationTargetException + +/** + * Closes [closeable] when [observed] becomes only phantom reachable. + * + * This is a wrapper around a Java 9+ [java.lang.ref.Cleaner], or a no-op in older Java versions. + */ +@JvmSynthetic +internal fun closeWhenPhantomReachable(observed: Any, closeable: AutoCloseable) { + check(observed !== closeable) { + "`observed` cannot be the same object as `closeable` because it would never become phantom reachable" + } + closeWhenPhantomReachable(observed, closeable::close) +} + +/** + * Calls [close] when [observed] becomes only phantom reachable. + * + * This is a wrapper around a Java 9+ [java.lang.ref.Cleaner], or a no-op in older Java versions. + */ +@JvmSynthetic +internal fun closeWhenPhantomReachable(observed: Any, close: () -> Unit) { + closeWhenPhantomReachable?.let { it(observed, close) } +} + +private val closeWhenPhantomReachable: ((Any, () -> Unit) -> Unit)? by lazy { + try { + val cleanerClass = Class.forName("java.lang.ref.Cleaner") + val cleanerCreate = cleanerClass.getMethod("create") + val cleanerRegister = + cleanerClass.getMethod("register", Any::class.java, Runnable::class.java) + val cleanerObject = cleanerCreate.invoke(null); + + { observed, close -> + try { + cleanerRegister.invoke(cleanerObject, observed, Runnable { close() }) + } catch (e: ReflectiveOperationException) { + if (e is InvocationTargetException) { + when (val cause = e.cause) { + is RuntimeException, + is Error -> throw cause + } + } + throw StagehandException("Unexpected reflective invocation failure", e) + } + } + } catch (e: ReflectiveOperationException) { + // We're running Java 8, which has no Cleaner. + null + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt new file mode 100644 index 0000000..cc3cebb --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt @@ -0,0 +1,58 @@ +package com.stagehand.api.core + +import java.util.concurrent.Callable +import java.util.concurrent.ExecutorService +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit + +/** + * A delegating wrapper around an [ExecutorService] that shuts it down once it's only phantom + * reachable. + * + * This class ensures the [ExecutorService] is shut down even if the user forgets to do it. + */ +internal class PhantomReachableExecutorService(private val executorService: ExecutorService) : + ExecutorService { + init { + closeWhenPhantomReachable(this) { executorService.shutdown() } + } + + override fun execute(command: Runnable) = executorService.execute(command) + + override fun shutdown() = executorService.shutdown() + + override fun shutdownNow(): MutableList = executorService.shutdownNow() + + override fun isShutdown(): Boolean = executorService.isShutdown + + override fun isTerminated(): Boolean = executorService.isTerminated + + override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean = + executorService.awaitTermination(timeout, unit) + + override fun submit(task: Callable): Future = executorService.submit(task) + + override fun submit(task: Runnable, result: T): Future = + executorService.submit(task, result) + + override fun submit(task: Runnable): Future<*> = executorService.submit(task) + + override fun invokeAll( + tasks: MutableCollection> + ): MutableList> = executorService.invokeAll(tasks) + + override fun invokeAll( + tasks: MutableCollection>, + timeout: Long, + unit: TimeUnit, + ): MutableList> = executorService.invokeAll(tasks, timeout, unit) + + override fun invokeAny(tasks: MutableCollection>): T = + executorService.invokeAny(tasks) + + override fun invokeAny( + tasks: MutableCollection>, + timeout: Long, + unit: TimeUnit, + ): T = executorService.invokeAny(tasks, timeout, unit) +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt new file mode 100644 index 0000000..8d82484 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt @@ -0,0 +1,23 @@ +package com.stagehand.api.core + +import java.time.Duration +import java.util.concurrent.CompletableFuture + +/** + * A delegating wrapper around a [Sleeper] that closes it once it's only phantom reachable. + * + * This class ensures the [Sleeper] is closed even if the user forgets to do it. + */ +internal class PhantomReachableSleeper(private val sleeper: Sleeper) : Sleeper { + + init { + closeWhenPhantomReachable(this, sleeper) + } + + override fun sleep(duration: Duration) = sleeper.sleep(duration) + + override fun sleepAsync(duration: Duration): CompletableFuture = + sleeper.sleepAsync(duration) + + override fun close() = sleeper.close() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt new file mode 100644 index 0000000..0da40de --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt @@ -0,0 +1,24 @@ +@file:JvmName("PrepareRequest") + +package com.stagehand.api.core + +import com.stagehand.api.core.http.HttpRequest +import java.util.concurrent.CompletableFuture + +@JvmSynthetic +internal fun HttpRequest.prepare(clientOptions: ClientOptions, params: Params): HttpRequest = + toBuilder() + .putAllQueryParams(clientOptions.queryParams) + .replaceAllQueryParams(params._queryParams()) + .putAllHeaders(clientOptions.headers) + .replaceAllHeaders(params._headers()) + .build() + +@JvmSynthetic +internal fun HttpRequest.prepareAsync( + clientOptions: ClientOptions, + params: Params, +): CompletableFuture = + // This async version exists to make it easier to add async specific preparation logic in the + // future. + CompletableFuture.completedFuture(prepare(clientOptions, params)) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt new file mode 100644 index 0000000..f2e9de2 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt @@ -0,0 +1,42 @@ +@file:JvmName("Properties") + +package com.stagehand.api.core + +import com.stagehand.api.client.StagehandClient + +fun getOsArch(): String { + val osArch = System.getProperty("os.arch") + + return when (osArch) { + null -> "unknown" + "i386", + "x32", + "x86" -> "x32" + "amd64", + "x86_64" -> "x64" + "arm" -> "arm" + "aarch64" -> "arm64" + else -> "other:$osArch" + } +} + +fun getOsName(): String { + val osName = System.getProperty("os.name") + val vendorUrl = System.getProperty("java.vendor.url") + + return when { + osName == null -> "Unknown" + osName.startsWith("Linux") && vendorUrl == "http://www.android.com/" -> "Android" + osName.startsWith("Linux") -> "Linux" + osName.startsWith("Mac OS") -> "MacOS" + osName.startsWith("Windows") -> "Windows" + else -> "Other:$osName" + } +} + +fun getOsVersion(): String = System.getProperty("os.version", "unknown") + +fun getPackageVersion(): String = + StagehandClient::class.java.`package`.implementationVersion ?: "unknown" + +fun getJavaVersion(): String = System.getProperty("java.version", "unknown") diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt new file mode 100644 index 0000000..10fb92a --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt @@ -0,0 +1,46 @@ +package com.stagehand.api.core + +import java.time.Duration + +class RequestOptions private constructor(val responseValidation: Boolean?, val timeout: Timeout?) { + + companion object { + + private val NONE = builder().build() + + @JvmStatic fun none() = NONE + + @JvmSynthetic + internal fun from(clientOptions: ClientOptions): RequestOptions = + builder() + .responseValidation(clientOptions.responseValidation) + .timeout(clientOptions.timeout) + .build() + + @JvmStatic fun builder() = Builder() + } + + fun applyDefaults(options: RequestOptions): RequestOptions = + RequestOptions( + responseValidation = responseValidation ?: options.responseValidation, + timeout = + if (options.timeout != null && timeout != null) timeout.assign(options.timeout) + else timeout ?: options.timeout, + ) + + class Builder internal constructor() { + + private var responseValidation: Boolean? = null + private var timeout: Timeout? = null + + fun responseValidation(responseValidation: Boolean) = apply { + this.responseValidation = responseValidation + } + + fun timeout(timeout: Timeout) = apply { this.timeout = timeout } + + fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build()) + + fun build(): RequestOptions = RequestOptions(responseValidation, timeout) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt new file mode 100644 index 0000000..bccd778 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt @@ -0,0 +1,21 @@ +package com.stagehand.api.core + +import java.time.Duration +import java.util.concurrent.CompletableFuture + +/** + * An interface for delaying execution for a specified amount of time. + * + * Useful for testing and cleaning up resources. + */ +interface Sleeper : AutoCloseable { + + /** Synchronously pauses execution for the given [duration]. */ + fun sleep(duration: Duration) + + /** Asynchronously pauses execution for the given [duration]. */ + fun sleepAsync(duration: Duration): CompletableFuture + + /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */ + override fun close() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt new file mode 100644 index 0000000..23d9885 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt @@ -0,0 +1,171 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.core + +import java.time.Duration +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** A class containing timeouts for various processing phases of a request. */ +class Timeout +private constructor( + private val connect: Duration?, + private val read: Duration?, + private val write: Duration?, + private val request: Duration?, +) { + + /** + * The maximum time allowed to establish a connection with a host. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `Duration.ofMinutes(1)`. + */ + fun connect(): Duration = connect ?: Duration.ofMinutes(1) + + /** + * The maximum time allowed between two data packets when waiting for the server’s response. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `request()`. + */ + fun read(): Duration = read ?: request() + + /** + * The maximum time allowed between two data packets when sending the request to the server. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `request()`. + */ + fun write(): Duration = write ?: request() + + /** + * The maximum time allowed for a complete HTTP call, not including retries. + * + * This includes resolving DNS, connecting, writing the request body, server processing, as well + * as reading the response body. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `Duration.ofMinutes(1)`. + */ + fun request(): Duration = request ?: Duration.ofMinutes(1) + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun default() = builder().build() + + /** Returns a mutable builder for constructing an instance of [Timeout]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Timeout]. */ + class Builder internal constructor() { + + private var connect: Duration? = null + private var read: Duration? = null + private var write: Duration? = null + private var request: Duration? = null + + @JvmSynthetic + internal fun from(timeout: Timeout) = apply { + connect = timeout.connect + read = timeout.read + write = timeout.write + request = timeout.request + } + + /** + * The maximum time allowed to establish a connection with a host. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `Duration.ofMinutes(1)`. + */ + fun connect(connect: Duration?) = apply { this.connect = connect } + + /** Alias for calling [Builder.connect] with `connect.orElse(null)`. */ + fun connect(connect: Optional) = connect(connect.getOrNull()) + + /** + * The maximum time allowed between two data packets when waiting for the server’s response. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `request()`. + */ + fun read(read: Duration?) = apply { this.read = read } + + /** Alias for calling [Builder.read] with `read.orElse(null)`. */ + fun read(read: Optional) = read(read.getOrNull()) + + /** + * The maximum time allowed between two data packets when sending the request to the server. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `request()`. + */ + fun write(write: Duration?) = apply { this.write = write } + + /** Alias for calling [Builder.write] with `write.orElse(null)`. */ + fun write(write: Optional) = write(write.getOrNull()) + + /** + * The maximum time allowed for a complete HTTP call, not including retries. + * + * This includes resolving DNS, connecting, writing the request body, server processing, as + * well as reading the response body. + * + * A value of [Duration.ZERO] means there's no timeout. + * + * Defaults to `Duration.ofMinutes(1)`. + */ + fun request(request: Duration?) = apply { this.request = request } + + /** Alias for calling [Builder.request] with `request.orElse(null)`. */ + fun request(request: Optional) = request(request.getOrNull()) + + /** + * Returns an immutable instance of [Timeout]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Timeout = Timeout(connect, read, write, request) + } + + @JvmSynthetic + internal fun assign(target: Timeout): Timeout = + target + .toBuilder() + .apply { + connect?.let(this::connect) + read?.let(this::read) + write?.let(this::write) + request?.let(this::request) + } + .build() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Timeout && + connect == other.connect && + read == other.read && + write == other.write && + request == other.request + } + + override fun hashCode(): Int = Objects.hash(connect, read, write, request) + + override fun toString() = + "Timeout{connect=$connect, read=$read, write=$write, request=$request}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt new file mode 100644 index 0000000..7e8118b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt @@ -0,0 +1,115 @@ +@file:JvmName("Utils") + +package com.stagehand.api.core + +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.SortedMap +import java.util.concurrent.CompletableFuture +import java.util.concurrent.locks.Lock + +@JvmSynthetic +internal fun T?.getOrThrow(name: String): T = + this ?: throw StagehandInvalidDataException("`${name}` is not present") + +@JvmSynthetic +internal fun List.toImmutable(): List = + if (isEmpty()) Collections.emptyList() else Collections.unmodifiableList(toList()) + +@JvmSynthetic +internal fun Map.toImmutable(): Map = + if (isEmpty()) immutableEmptyMap() else Collections.unmodifiableMap(toMap()) + +@JvmSynthetic internal fun immutableEmptyMap(): Map = Collections.emptyMap() + +@JvmSynthetic +internal fun , V> SortedMap.toImmutable(): SortedMap = + if (isEmpty()) Collections.emptySortedMap() + else Collections.unmodifiableSortedMap(toSortedMap(comparator())) + +/** + * Returns all elements that yield the largest value for the given function, or an empty list if + * there are zero elements. + * + * This is similar to [Sequence.maxByOrNull] except it returns _all_ elements that yield the largest + * value; not just the first one. + */ +@JvmSynthetic +internal fun > Sequence.allMaxBy(selector: (T) -> R): List { + var maxValue: R? = null + val maxElements = mutableListOf() + + val iterator = iterator() + while (iterator.hasNext()) { + val element = iterator.next() + val value = selector(element) + if (maxValue == null || value > maxValue) { + maxValue = value + maxElements.clear() + maxElements.add(element) + } else if (value == maxValue) { + maxElements.add(element) + } + } + + return maxElements +} + +/** + * Returns whether [this] is equal to [other]. + * + * This differs from [Object.equals] because it also deeply equates arrays based on their contents, + * even when there are arrays directly nested within other arrays. + */ +@JvmSynthetic +internal infix fun Any?.contentEquals(other: Any?): Boolean = + arrayOf(this).contentDeepEquals(arrayOf(other)) + +/** + * Returns a hash of the given sequence of [values]. + * + * This differs from [java.util.Objects.hash] because it also deeply hashes arrays based on their + * contents, even when there are arrays directly nested within other arrays. + */ +@JvmSynthetic internal fun contentHash(vararg values: Any?): Int = values.contentDeepHashCode() + +/** + * Returns a [String] representation of [this]. + * + * This differs from [Object.toString] because it also deeply stringifies arrays based on their + * contents, even when there are arrays directly nested within other arrays. + */ +@JvmSynthetic +internal fun Any?.contentToString(): String { + var string = arrayOf(this).contentDeepToString() + if (string.startsWith('[')) { + string = string.substring(1) + } + if (string.endsWith(']')) { + string = string.substring(0, string.length - 1) + } + return string +} + +internal interface Enum + +/** + * Executes the given [action] while holding the lock, returning a [CompletableFuture] with the + * result. + * + * @param action The asynchronous action to execute while holding the lock + * @return A [CompletableFuture] that completes with the result of the action + */ +@JvmSynthetic +internal fun Lock.withLockAsync(action: () -> CompletableFuture): CompletableFuture { + lock() + val future = + try { + action() + } catch (e: Throwable) { + unlock() + throw e + } + future.whenComplete { _, _ -> unlock() } + return future +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt new file mode 100644 index 0000000..8410d97 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt @@ -0,0 +1,723 @@ +package com.stagehand.api.core + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.BeanProperty +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JavaType +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.databind.node.JsonNodeType.ARRAY +import com.fasterxml.jackson.databind.node.JsonNodeType.BINARY +import com.fasterxml.jackson.databind.node.JsonNodeType.BOOLEAN +import com.fasterxml.jackson.databind.node.JsonNodeType.MISSING +import com.fasterxml.jackson.databind.node.JsonNodeType.NULL +import com.fasterxml.jackson.databind.node.JsonNodeType.NUMBER +import com.fasterxml.jackson.databind.node.JsonNodeType.OBJECT +import com.fasterxml.jackson.databind.node.JsonNodeType.POJO +import com.fasterxml.jackson.databind.node.JsonNodeType.STRING +import com.fasterxml.jackson.databind.ser.std.NullSerializer +import com.stagehand.api.errors.StagehandInvalidDataException +import java.io.InputStream +import java.util.Objects +import java.util.Optional + +/** + * A class representing a serializable JSON field. + * + * It can either be a [KnownValue] value of type [T], matching the type the SDK expects, or an + * arbitrary JSON value that bypasses the type system (via [JsonValue]). + */ +@JsonDeserialize(using = JsonField.Deserializer::class) +sealed class JsonField { + + /** + * Returns whether this field is missing, which means it will be omitted from the serialized + * JSON entirely. + */ + fun isMissing(): Boolean = this is JsonMissing + + /** Whether this field is explicitly set to `null`. */ + fun isNull(): Boolean = this is JsonNull + + /** + * Returns an [Optional] containing this field's "known" value, meaning it matches the type the + * SDK expects, or an empty [Optional] if this field contains an arbitrary [JsonValue]. + * + * This is the opposite of [asUnknown]. + */ + fun asKnown(): + Optional< + // Safe because `Optional` is effectively covariant, but Kotlin doesn't know that. + @UnsafeVariance + T + > = Optional.ofNullable((this as? KnownValue)?.value) + + /** + * Returns an [Optional] containing this field's arbitrary [JsonValue], meaning it mismatches + * the type the SDK expects, or an empty [Optional] if this field contains a "known" value. + * + * This is the opposite of [asKnown]. + */ + fun asUnknown(): Optional = Optional.ofNullable(this as? JsonValue) + + /** + * Returns an [Optional] containing this field's boolean value, or an empty [Optional] if it + * doesn't contain a boolean. + * + * This method checks for both a [KnownValue] containing a boolean and for [JsonBoolean]. + */ + fun asBoolean(): Optional = + when (this) { + is JsonBoolean -> Optional.of(value) + is KnownValue -> Optional.ofNullable(value as? Boolean) + else -> Optional.empty() + } + + /** + * Returns an [Optional] containing this field's numerical value, or an empty [Optional] if it + * doesn't contain a number. + * + * This method checks for both a [KnownValue] containing a number and for [JsonNumber]. + */ + fun asNumber(): Optional = + when (this) { + is JsonNumber -> Optional.of(value) + is KnownValue -> Optional.ofNullable(value as? Number) + else -> Optional.empty() + } + + /** + * Returns an [Optional] containing this field's string value, or an empty [Optional] if it + * doesn't contain a string. + * + * This method checks for both a [KnownValue] containing a string and for [JsonString]. + */ + fun asString(): Optional = + when (this) { + is JsonString -> Optional.of(value) + is KnownValue -> Optional.ofNullable(value as? String) + else -> Optional.empty() + } + + fun asStringOrThrow(): String = + asString().orElseThrow { StagehandInvalidDataException("Value is not a string") } + + /** + * Returns an [Optional] containing this field's list value, or an empty [Optional] if it + * doesn't contain a list. + * + * This method checks for both a [KnownValue] containing a list and for [JsonArray]. + */ + fun asArray(): Optional> = + when (this) { + is JsonArray -> Optional.of(values) + is KnownValue -> + Optional.ofNullable( + (value as? List<*>)?.map { + try { + JsonValue.from(it) + } catch (e: IllegalArgumentException) { + // The known value is a list, but not all values are convertible to + // `JsonValue`. + return Optional.empty() + } + } + ) + else -> Optional.empty() + } + + /** + * Returns an [Optional] containing this field's map value, or an empty [Optional] if it doesn't + * contain a map. + * + * This method checks for both a [KnownValue] containing a map and for [JsonObject]. + */ + fun asObject(): Optional> = + when (this) { + is JsonObject -> Optional.of(values) + is KnownValue -> + Optional.ofNullable( + (value as? Map<*, *>) + ?.map { (key, value) -> + if (key !is String) { + return Optional.empty() + } + + val jsonValue = + try { + JsonValue.from(value) + } catch (e: IllegalArgumentException) { + // The known value is a map, but not all items are convertible + // to `JsonValue`. + return Optional.empty() + } + + key to jsonValue + } + ?.toMap() + ) + else -> Optional.empty() + } + + @JvmSynthetic + internal fun getRequired(name: String): T = + when (this) { + is KnownValue -> value + is JsonMissing -> throw StagehandInvalidDataException("`$name` is not set") + is JsonNull -> throw StagehandInvalidDataException("`$name` is null") + else -> throw StagehandInvalidDataException("`$name` is invalid, received $this") + } + + @JvmSynthetic + internal fun getOptional( + name: String + ): Optional< + // Safe because `Optional` is effectively covariant, but Kotlin doesn't know that. + @UnsafeVariance + T + > = + when (this) { + is KnownValue -> Optional.of(value) + is JsonMissing, + is JsonNull -> Optional.empty() + else -> throw StagehandInvalidDataException("`$name` is invalid, received $this") + } + + @JvmSynthetic + internal fun map(transform: (T) -> R): JsonField = + when (this) { + is KnownValue -> KnownValue.of(transform(value)) + is JsonValue -> this + } + + @JvmSynthetic internal fun accept(consume: (T) -> Unit) = asKnown().ifPresent(consume) + + /** Returns the result of calling the [visitor] method corresponding to this field's state. */ + fun accept(visitor: Visitor): R = + when (this) { + is KnownValue -> visitor.visitKnown(value) + is JsonValue -> accept(visitor as JsonValue.Visitor) + } + + /** + * An interface that defines how to map each possible state of a `JsonField` to a value of + * type [R]. + */ + interface Visitor : JsonValue.Visitor { + + fun visitKnown(value: T): R = visitDefault() + } + + companion object { + + /** Returns a [JsonField] containing the given "known" [value]. */ + @JvmStatic fun of(value: T): JsonField = KnownValue.of(value) + + /** + * Returns a [JsonField] containing the given "known" [value], or [JsonNull] if [value] is + * null. + */ + @JvmStatic + fun ofNullable(value: T?): JsonField = + when (value) { + null -> JsonNull.of() + else -> KnownValue.of(value) + } + } + + /** + * This class is a Jackson filter that can be used to exclude missing properties from objects. + * This filter should not be used directly and should instead use the @ExcludeMissing + * annotation. + */ + class IsMissing { + + override fun equals(other: Any?): Boolean = other is JsonMissing + + override fun hashCode(): Int = Objects.hash() + } + + class Deserializer(private val type: JavaType? = null) : + BaseDeserializer>(JsonField::class) { + + override fun createContextual( + context: DeserializationContext, + property: BeanProperty?, + ): JsonDeserializer> = Deserializer(context.contextualType?.containedType(0)) + + override fun ObjectCodec.deserialize(node: JsonNode): JsonField<*> = + type?.let { tryDeserialize(node, type) }?.let { of(it) } + ?: JsonValue.fromJsonNode(node) + + override fun getNullValue(context: DeserializationContext): JsonField<*> = JsonNull.of() + } +} + +/** + * A class representing an arbitrary JSON value. + * + * It is immutable and assignable to any [JsonField], regardless of its expected type (i.e. its + * generic type argument). + */ +@JsonDeserialize(using = JsonValue.Deserializer::class) +sealed class JsonValue : JsonField() { + + fun convert(type: TypeReference): R? = JSON_MAPPER.convertValue(this, type) + + fun convert(type: Class): R? = JSON_MAPPER.convertValue(this, type) + + /** Returns the result of calling the [visitor] method corresponding to this value's variant. */ + fun accept(visitor: Visitor): R = + when (this) { + is JsonMissing -> visitor.visitMissing() + is JsonNull -> visitor.visitNull() + is JsonBoolean -> visitor.visitBoolean(value) + is JsonNumber -> visitor.visitNumber(value) + is JsonString -> visitor.visitString(value) + is JsonArray -> visitor.visitArray(values) + is JsonObject -> visitor.visitObject(values) + } + + /** + * An interface that defines how to map each variant state of a [JsonValue] to a value of type + * [R]. + */ + interface Visitor { + + fun visitNull(): R = visitDefault() + + fun visitMissing(): R = visitDefault() + + fun visitBoolean(value: Boolean): R = visitDefault() + + fun visitNumber(value: Number): R = visitDefault() + + fun visitString(value: String): R = visitDefault() + + fun visitArray(values: List): R = visitDefault() + + fun visitObject(values: Map): R = visitDefault() + + /** + * The default implementation for unimplemented visitor methods. + * + * @throws IllegalArgumentException in the default implementation. + */ + fun visitDefault(): R = throw IllegalArgumentException("Unexpected value") + } + + companion object { + + private val JSON_MAPPER = jsonMapper() + + /** + * Converts the given [value] to a [JsonValue]. + * + * This method works best on primitive types, [List] values, [Map] values, and nested + * combinations of these. For example: + * ```java + * // Create primitive JSON values + * JsonValue nullValue = JsonValue.from(null); + * JsonValue booleanValue = JsonValue.from(true); + * JsonValue numberValue = JsonValue.from(42); + * JsonValue stringValue = JsonValue.from("Hello World!"); + * + * // Create a JSON array value equivalent to `["Hello", "World"]` + * JsonValue arrayValue = JsonValue.from(List.of("Hello", "World")); + * + * // Create a JSON object value equivalent to `{ "a": 1, "b": 2 }` + * JsonValue objectValue = JsonValue.from(Map.of( + * "a", 1, + * "b", 2 + * )); + * + * // Create an arbitrarily nested JSON equivalent to: + * // { + * // "a": [1, 2], + * // "b": [3, 4] + * // } + * JsonValue complexValue = JsonValue.from(Map.of( + * "a", List.of(1, 2), + * "b", List.of(3, 4) + * )); + * ``` + * + * @throws IllegalArgumentException if [value] is not JSON serializable. + */ + @JvmStatic + fun from(value: Any?): JsonValue = + when (value) { + null -> JsonNull.of() + is JsonValue -> value + else -> JSON_MAPPER.convertValue(value, JsonValue::class.java) + } + + /** + * Returns a [JsonValue] converted from the given Jackson [JsonNode]. + * + * @throws IllegalStateException for unsupported node types. + */ + @JvmStatic + fun fromJsonNode(node: JsonNode): JsonValue = + when (node.nodeType) { + MISSING -> JsonMissing.of() + NULL -> JsonNull.of() + BOOLEAN -> JsonBoolean.of(node.booleanValue()) + NUMBER -> JsonNumber.of(node.numberValue()) + STRING -> JsonString.of(node.textValue()) + ARRAY -> + JsonArray.of(node.elements().asSequence().map { fromJsonNode(it) }.toList()) + OBJECT -> + JsonObject.of( + node.fields().asSequence().map { it.key to fromJsonNode(it.value) }.toMap() + ) + BINARY, + POJO, + null -> throw IllegalStateException("Unexpected JsonNode type: ${node.nodeType}") + } + } + + class Deserializer : BaseDeserializer(JsonValue::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): JsonValue = fromJsonNode(node) + + override fun getNullValue(context: DeserializationContext?): JsonValue = JsonNull.of() + } +} + +/** + * A class representing a "known" JSON serializable value of type [T], matching the type the SDK + * expects. + * + * It is assignable to `JsonField`. + */ +class KnownValue +private constructor( + @com.fasterxml.jackson.annotation.JsonValue @get:JvmName("value") val value: T +) : JsonField() { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is KnownValue<*> && value contentEquals other.value + } + + override fun hashCode() = contentHash(value) + + override fun toString() = value.contentToString() + + companion object { + + /** Returns a [KnownValue] containing the given [value]. */ + @JsonCreator @JvmStatic fun of(value: T) = KnownValue(value) + } +} + +/** + * A [JsonValue] representing an omitted JSON field. + * + * An instance of this class will cause a JSON field to be omitted from the serialized JSON + * entirely. + */ +@JsonSerialize(using = JsonMissing.Serializer::class) +class JsonMissing : JsonValue() { + + override fun toString() = "" + + companion object { + + private val INSTANCE: JsonMissing = JsonMissing() + + /** Returns the singleton instance of [JsonMissing]. */ + @JvmStatic fun of() = INSTANCE + } + + class Serializer : BaseSerializer(JsonMissing::class) { + + override fun serialize( + value: JsonMissing, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + throw IllegalStateException("JsonMissing cannot be serialized") + } + } +} + +/** A [JsonValue] representing a JSON `null` value. */ +@JsonSerialize(using = NullSerializer::class) +class JsonNull : JsonValue() { + + override fun toString() = "null" + + companion object { + + private val INSTANCE: JsonNull = JsonNull() + + /** Returns the singleton instance of [JsonMissing]. */ + @JsonCreator @JvmStatic fun of() = INSTANCE + } +} + +/** A [JsonValue] representing a JSON boolean value. */ +class JsonBoolean +private constructor( + @get:com.fasterxml.jackson.annotation.JsonValue @get:JvmName("value") val value: Boolean +) : JsonValue() { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is JsonBoolean && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + + companion object { + + /** Returns a [JsonBoolean] containing the given [value]. */ + @JsonCreator @JvmStatic fun of(value: Boolean) = JsonBoolean(value) + } +} + +/** A [JsonValue] representing a JSON number value. */ +class JsonNumber +private constructor( + @get:com.fasterxml.jackson.annotation.JsonValue @get:JvmName("value") val value: Number +) : JsonValue() { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is JsonNumber && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + + companion object { + + /** Returns a [JsonNumber] containing the given [value]. */ + @JsonCreator @JvmStatic fun of(value: Number) = JsonNumber(value) + } +} + +/** A [JsonValue] representing a JSON string value. */ +class JsonString +private constructor( + @get:com.fasterxml.jackson.annotation.JsonValue @get:JvmName("value") val value: String +) : JsonValue() { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is JsonString && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value + + companion object { + + /** Returns a [JsonString] containing the given [value]. */ + @JsonCreator @JvmStatic fun of(value: String) = JsonString(value) + } +} + +/** A [JsonValue] representing a JSON array value. */ +class JsonArray +private constructor( + @get:com.fasterxml.jackson.annotation.JsonValue + @get:JvmName("values") + val values: List +) : JsonValue() { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is JsonArray && values == other.values + } + + override fun hashCode() = values.hashCode() + + override fun toString() = values.toString() + + companion object { + + /** Returns a [JsonArray] containing the given [values]. */ + @JsonCreator @JvmStatic fun of(values: List) = JsonArray(values.toImmutable()) + } +} + +/** A [JsonValue] representing a JSON object value. */ +class JsonObject +private constructor( + @get:com.fasterxml.jackson.annotation.JsonValue + @get:JvmName("values") + val values: Map +) : JsonValue() { + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is JsonObject && values == other.values + } + + override fun hashCode() = values.hashCode() + + override fun toString() = values.toString() + + companion object { + + /** Returns a [JsonObject] containing the given [values]. */ + @JsonCreator + @JvmStatic + fun of(values: Map) = JsonObject(values.toImmutable()) + } +} + +/** A Jackson annotation for excluding fields set to [JsonMissing] from the serialized JSON. */ +@JacksonAnnotationsInside +@JsonInclude(JsonInclude.Include.CUSTOM, valueFilter = JsonField.IsMissing::class) +annotation class ExcludeMissing + +/** A class representing a field in a `multipart/form-data` request. */ +class MultipartField +private constructor( + /** A [JsonField] value, which will be serialized to zero or more parts. */ + @get:com.fasterxml.jackson.annotation.JsonValue @get:JvmName("value") val value: JsonField, + /** A content type for the serialized parts. */ + @get:JvmName("contentType") val contentType: String, + private val filename: String?, +) { + + companion object { + + /** + * Returns a [MultipartField] containing the given [value] as a [KnownValue]. + * + * [contentType] will be set to `application/octet-stream` if [value] is binary data, or + * `text/plain; charset=utf-8` otherwise. + */ + @JvmStatic fun of(value: T?) = builder().value(value).build() + + /** + * Returns a [MultipartField] containing the given [value]. + * + * [contentType] will be set to `application/octet-stream` if [value] is binary data, or + * `text/plain; charset=utf-8` otherwise. + */ + @JvmStatic fun of(value: JsonField) = builder().value(value).build() + + /** + * Returns a mutable builder for constructing an instance of [MultipartField]. + * + * The following fields are required: + * ```java + * .value() + * ``` + * + * If [contentType] is unset, then it will be set to `application/octet-stream` if [value] + * is binary data, or `text/plain; charset=utf-8` otherwise. + */ + @JvmStatic fun builder() = Builder() + } + + /** Returns the filename directive that will be included in the serialized field. */ + fun filename(): Optional = Optional.ofNullable(filename) + + @JvmSynthetic + internal fun map(transform: (T) -> R): MultipartField = + builder().value(value.map(transform)).contentType(contentType).filename(filename).build() + + /** A builder for [MultipartField]. */ + class Builder internal constructor() { + + private var value: JsonField? = null + private var contentType: String? = null + private var filename: String? = null + + fun value(value: JsonField) = apply { this.value = value } + + fun value(value: T?) = value(JsonField.ofNullable(value)) + + fun contentType(contentType: String) = apply { this.contentType = contentType } + + fun filename(filename: String?) = apply { this.filename = filename } + + /** Alias for calling [Builder.filename] with `filename.orElse(null)`. */ + fun filename(filename: Optional) = filename(filename.orElse(null)) + + /** + * Returns an immutable instance of [MultipartField]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .value() + * ``` + * + * If [contentType] is unset, then it will be set to `application/octet-stream` if [value] + * is binary data, or `text/plain; charset=utf-8` otherwise. + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): MultipartField { + val value = checkRequired("value", value) + return MultipartField( + value, + contentType + ?: if ( + value is KnownValue && + (value.value is InputStream || value.value is ByteArray) + ) + "application/octet-stream" + else "text/plain; charset=utf-8", + filename, + ) + } + } + + private val hashCode: Int by lazy { contentHash(value, contentType, filename) } + + override fun hashCode(): Int = hashCode + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is MultipartField<*> && + value == other.value && + contentType == other.contentType && + filename == other.filename + } + + override fun toString(): String = + "MultipartField{value=$value, contentType=$contentType, filename=$filename}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt new file mode 100644 index 0000000..08b3c7f --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt @@ -0,0 +1,84 @@ +// File generated from our OpenAPI spec by Stainless. + +@file:JvmName("ErrorHandler") + +package com.stagehand.api.core.handlers + +import com.fasterxml.jackson.databind.json.JsonMapper +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.http.HttpResponse +import com.stagehand.api.core.http.HttpResponse.Handler +import com.stagehand.api.errors.BadRequestException +import com.stagehand.api.errors.InternalServerException +import com.stagehand.api.errors.NotFoundException +import com.stagehand.api.errors.PermissionDeniedException +import com.stagehand.api.errors.RateLimitException +import com.stagehand.api.errors.UnauthorizedException +import com.stagehand.api.errors.UnexpectedStatusCodeException +import com.stagehand.api.errors.UnprocessableEntityException + +@JvmSynthetic +internal fun errorBodyHandler(jsonMapper: JsonMapper): Handler { + val handler = jsonHandler(jsonMapper) + + return object : Handler { + override fun handle(response: HttpResponse): JsonValue = + try { + handler.handle(response) + } catch (e: Exception) { + JsonMissing.of() + } + } +} + +@JvmSynthetic +internal fun errorHandler(errorBodyHandler: Handler): Handler = + object : Handler { + override fun handle(response: HttpResponse): HttpResponse = + when (val statusCode = response.statusCode()) { + in 200..299 -> response + 400 -> + throw BadRequestException.builder() + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + 401 -> + throw UnauthorizedException.builder() + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + 403 -> + throw PermissionDeniedException.builder() + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + 404 -> + throw NotFoundException.builder() + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + 422 -> + throw UnprocessableEntityException.builder() + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + 429 -> + throw RateLimitException.builder() + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + in 500..599 -> + throw InternalServerException.builder() + .statusCode(statusCode) + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + else -> + throw UnexpectedStatusCodeException.builder() + .statusCode(statusCode) + .headers(response.headers()) + .body(errorBodyHandler.handle(response)) + .build() + } + } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt new file mode 100644 index 0000000..dc8d9e5 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt @@ -0,0 +1,20 @@ +@file:JvmName("JsonHandler") + +package com.stagehand.api.core.handlers + +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.http.HttpResponse +import com.stagehand.api.core.http.HttpResponse.Handler +import com.stagehand.api.errors.StagehandInvalidDataException + +@JvmSynthetic +internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler = + object : Handler { + override fun handle(response: HttpResponse): T = + try { + jsonMapper.readValue(response.body(), jacksonTypeRef()) + } catch (e: Exception) { + throw StagehandInvalidDataException("Error reading response", e) + } + } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt new file mode 100644 index 0000000..9f7fb80 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt @@ -0,0 +1,13 @@ +@file:JvmName("StringHandler") + +package com.stagehand.api.core.handlers + +import com.stagehand.api.core.http.HttpResponse +import com.stagehand.api.core.http.HttpResponse.Handler + +@JvmSynthetic internal fun stringHandler(): Handler = StringHandlerInternal + +private object StringHandlerInternal : Handler { + override fun handle(response: HttpResponse): String = + response.body().readBytes().toString(Charsets.UTF_8) +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt new file mode 100644 index 0000000..23948e6 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt @@ -0,0 +1,157 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.http.AsyncStreamResponse.Handler +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import java.util.concurrent.atomic.AtomicReference + +/** + * A class providing access to an API response as an asynchronous stream of chunks of type [T], + * where each chunk can be individually processed as soon as it arrives instead of waiting on the + * full response. + */ +interface AsyncStreamResponse { + + /** + * Registers [handler] to be called for events of this stream. + * + * [handler]'s methods will be called in the client's configured or default thread pool. + * + * @throws IllegalStateException if [subscribe] has already been called. + */ + fun subscribe(handler: Handler): AsyncStreamResponse + + /** + * Registers [handler] to be called for events of this stream. + * + * [handler]'s methods will be called in the given [executor]. + * + * @throws IllegalStateException if [subscribe] has already been called. + */ + fun subscribe(handler: Handler, executor: Executor): AsyncStreamResponse + + /** + * Returns a future that completes when a stream is fully consumed, errors, or gets closed + * early. + */ + fun onCompleteFuture(): CompletableFuture + + /** + * Closes this resource, relinquishing any underlying resources. + * + * This is purposefully not inherited from [AutoCloseable] because this response should not be + * synchronously closed via try-with-resources. + */ + fun close() + + /** A class for handling streaming events. */ + fun interface Handler { + + /** Called whenever a chunk is received. */ + fun onNext(value: T) + + /** + * Called when a stream is fully consumed, errors, or gets closed early. + * + * [onNext] will not be called once this method is called. + * + * @param error Non-empty if the stream completed due to an error. + */ + fun onComplete(error: Optional) {} + } +} + +@JvmSynthetic +internal fun CompletableFuture>.toAsync(streamHandlerExecutor: Executor) = + PhantomReachableClosingAsyncStreamResponse( + object : AsyncStreamResponse { + + private val onCompleteFuture = CompletableFuture() + private val state = AtomicReference(State.NEW) + + init { + this@toAsync.whenComplete { _, error -> + // If an error occurs from the original future, then we should resolve the + // `onCompleteFuture` even if `subscribe` has not been called. + error?.let(onCompleteFuture::completeExceptionally) + } + } + + override fun subscribe(handler: Handler): AsyncStreamResponse = + subscribe(handler, streamHandlerExecutor) + + override fun subscribe( + handler: Handler, + executor: Executor, + ): AsyncStreamResponse = apply { + // TODO(JDK): Use `compareAndExchange` once targeting JDK 9. + check(state.compareAndSet(State.NEW, State.SUBSCRIBED)) { + if (state.get() == State.SUBSCRIBED) "Cannot subscribe more than once" + else "Cannot subscribe after the response is closed" + } + + this@toAsync.whenCompleteAsync( + { streamResponse, futureError -> + if (state.get() == State.CLOSED) { + // Avoid doing any work if `close` was called before the future + // completed. + return@whenCompleteAsync + } + + if (futureError != null) { + // An error occurred before we started passing chunks to the handler. + handler.onComplete(Optional.of(futureError)) + return@whenCompleteAsync + } + + var streamError: Throwable? = null + try { + streamResponse.stream().forEach(handler::onNext) + } catch (e: Throwable) { + streamError = e + } + + try { + handler.onComplete(Optional.ofNullable(streamError)) + } finally { + try { + // Notify completion via the `onCompleteFuture` as well. This is in + // a separate `try-finally` block so that we still complete the + // future if `handler.onComplete` throws. + if (streamError == null) { + onCompleteFuture.complete(null) + } else { + onCompleteFuture.completeExceptionally(streamError) + } + } finally { + close() + } + } + }, + executor, + ) + } + + override fun onCompleteFuture(): CompletableFuture = onCompleteFuture + + override fun close() { + val previousState = state.getAndSet(State.CLOSED) + if (previousState == State.CLOSED) { + return + } + + this@toAsync.whenComplete { streamResponse, error -> streamResponse?.close() } + // When the stream is closed, we should always consider it closed. If it closed due + // to an error, then we will have already completed the future earlier, and this + // will be a no-op. + onCompleteFuture.complete(null) + } + } + ) + +private enum class State { + NEW, + SUBSCRIBED, + CLOSED, +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt new file mode 100644 index 0000000..a6bfeb9 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt @@ -0,0 +1,115 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.core.http + +import com.stagehand.api.core.JsonArray +import com.stagehand.api.core.JsonBoolean +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonNull +import com.stagehand.api.core.JsonNumber +import com.stagehand.api.core.JsonObject +import com.stagehand.api.core.JsonString +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.toImmutable +import java.util.TreeMap + +class Headers +private constructor( + private val map: Map>, + @get:JvmName("size") val size: Int, +) { + + fun isEmpty(): Boolean = map.isEmpty() + + fun names(): Set = map.keys + + fun values(name: String): List = map[name].orEmpty() + + fun toBuilder(): Builder = Builder().putAll(map) + + companion object { + + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + + private val map: MutableMap> = + TreeMap(String.CASE_INSENSITIVE_ORDER) + private var size: Int = 0 + + fun put(name: String, value: JsonValue): Builder = apply { + when (value) { + is JsonMissing, + is JsonNull -> {} + is JsonBoolean -> put(name, value.value.toString()) + is JsonNumber -> put(name, value.value.toString()) + is JsonString -> put(name, value.value) + is JsonArray -> value.values.forEach { put(name, it) } + is JsonObject -> + value.values.forEach { (nestedName, value) -> put("$name.$nestedName", value) } + } + } + + fun put(name: String, value: String) = apply { + map.getOrPut(name) { mutableListOf() }.add(value) + size++ + } + + fun put(name: String, values: Iterable) = apply { values.forEach { put(name, it) } } + + fun putAll(headers: Map>) = apply { headers.forEach(::put) } + + fun putAll(headers: Headers) = apply { + headers.names().forEach { put(it, headers.values(it)) } + } + + fun replace(name: String, value: String) = apply { + remove(name) + put(name, value) + } + + fun replace(name: String, values: Iterable) = apply { + remove(name) + put(name, values) + } + + fun replaceAll(headers: Map>) = apply { + headers.forEach(::replace) + } + + fun replaceAll(headers: Headers) = apply { + headers.names().forEach { replace(it, headers.values(it)) } + } + + fun remove(name: String) = apply { size -= map.remove(name).orEmpty().size } + + fun removeAll(names: Set) = apply { names.forEach(::remove) } + + fun clear() = apply { + map.clear() + size = 0 + } + + fun build() = + Headers( + map.mapValuesTo(TreeMap(String.CASE_INSENSITIVE_ORDER)) { (_, values) -> + values.toImmutable() + } + .toImmutable(), + size, + ) + } + + override fun hashCode(): Int = map.hashCode() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && map == other.map + } + + override fun toString(): String = "Headers{map=$map}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt new file mode 100644 index 0000000..45d1240 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt @@ -0,0 +1,26 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.RequestOptions +import java.lang.AutoCloseable +import java.util.concurrent.CompletableFuture + +interface HttpClient : AutoCloseable { + + fun execute( + request: HttpRequest, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse + + fun execute(request: HttpRequest): HttpResponse = execute(request, RequestOptions.none()) + + fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + fun executeAsync(request: HttpRequest): CompletableFuture = + executeAsync(request, RequestOptions.none()) + + /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */ + override fun close() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt new file mode 100644 index 0000000..243d075 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt @@ -0,0 +1,13 @@ +package com.stagehand.api.core.http + +enum class HttpMethod { + GET, + HEAD, + POST, + PUT, + DELETE, + CONNECT, + OPTIONS, + TRACE, + PATCH, +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt new file mode 100644 index 0000000..e262cfa --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt @@ -0,0 +1,146 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.toImmutable + +class HttpRequest +private constructor( + @get:JvmName("method") val method: HttpMethod, + @get:JvmName("baseUrl") val baseUrl: String, + @get:JvmName("pathSegments") val pathSegments: List, + @get:JvmName("headers") val headers: Headers, + @get:JvmName("queryParams") val queryParams: QueryParams, + @get:JvmName("body") val body: HttpRequestBody?, +) { + + fun toBuilder(): Builder = Builder().from(this) + + override fun toString(): String = + "HttpRequest{method=$method, baseUrl=$baseUrl, pathSegments=$pathSegments, headers=$headers, queryParams=$queryParams, body=$body}" + + companion object { + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + + private var method: HttpMethod? = null + private var baseUrl: String? = null + private var pathSegments: MutableList = mutableListOf() + private var headers: Headers.Builder = Headers.builder() + private var queryParams: QueryParams.Builder = QueryParams.builder() + private var body: HttpRequestBody? = null + + @JvmSynthetic + internal fun from(request: HttpRequest) = apply { + method = request.method + baseUrl = request.baseUrl + pathSegments = request.pathSegments.toMutableList() + headers = request.headers.toBuilder() + queryParams = request.queryParams.toBuilder() + body = request.body + } + + fun method(method: HttpMethod) = apply { this.method = method } + + fun baseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl } + + fun addPathSegment(pathSegment: String) = apply { pathSegments.add(pathSegment) } + + fun addPathSegments(vararg pathSegments: String) = apply { + this.pathSegments.addAll(pathSegments) + } + + fun headers(headers: Headers) = apply { + this.headers.clear() + putAllHeaders(headers) + } + + fun headers(headers: Map>) = apply { + this.headers.clear() + putAllHeaders(headers) + } + + fun putHeader(name: String, value: String) = apply { headers.put(name, value) } + + fun putHeaders(name: String, values: Iterable) = apply { headers.put(name, values) } + + fun putAllHeaders(headers: Headers) = apply { this.headers.putAll(headers) } + + fun putAllHeaders(headers: Map>) = apply { + this.headers.putAll(headers) + } + + fun replaceHeaders(name: String, value: String) = apply { headers.replace(name, value) } + + fun replaceHeaders(name: String, values: Iterable) = apply { + headers.replace(name, values) + } + + fun replaceAllHeaders(headers: Headers) = apply { this.headers.replaceAll(headers) } + + fun replaceAllHeaders(headers: Map>) = apply { + this.headers.replaceAll(headers) + } + + fun removeHeaders(name: String) = apply { headers.remove(name) } + + fun removeAllHeaders(names: Set) = apply { headers.removeAll(names) } + + fun queryParams(queryParams: QueryParams) = apply { + this.queryParams.clear() + putAllQueryParams(queryParams) + } + + fun queryParams(queryParams: Map>) = apply { + this.queryParams.clear() + putAllQueryParams(queryParams) + } + + fun putQueryParam(key: String, value: String) = apply { queryParams.put(key, value) } + + fun putQueryParams(key: String, values: Iterable) = apply { + queryParams.put(key, values) + } + + fun putAllQueryParams(queryParams: QueryParams) = apply { + this.queryParams.putAll(queryParams) + } + + fun putAllQueryParams(queryParams: Map>) = apply { + this.queryParams.putAll(queryParams) + } + + fun replaceQueryParams(key: String, value: String) = apply { + queryParams.replace(key, value) + } + + fun replaceQueryParams(key: String, values: Iterable) = apply { + queryParams.replace(key, values) + } + + fun replaceAllQueryParams(queryParams: QueryParams) = apply { + this.queryParams.replaceAll(queryParams) + } + + fun replaceAllQueryParams(queryParams: Map>) = apply { + this.queryParams.replaceAll(queryParams) + } + + fun removeQueryParams(key: String) = apply { queryParams.remove(key) } + + fun removeAllQueryParams(keys: Set) = apply { queryParams.removeAll(keys) } + + fun body(body: HttpRequestBody) = apply { this.body = body } + + fun build(): HttpRequest = + HttpRequest( + checkRequired("method", method), + checkRequired("baseUrl", baseUrl), + pathSegments.toImmutable(), + headers.build(), + queryParams.build(), + body, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt new file mode 100644 index 0000000..98811cc --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt @@ -0,0 +1,130 @@ +// File generated from our OpenAPI spec by Stainless. + +@file:JvmName("HttpRequestBodies") + +package com.stagehand.api.core.http + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.databind.node.JsonNodeType +import com.stagehand.api.core.MultipartField +import com.stagehand.api.errors.StagehandInvalidDataException +import java.io.InputStream +import java.io.OutputStream +import kotlin.jvm.optionals.getOrNull +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder +import org.apache.hc.core5.http.ContentType +import org.apache.hc.core5.http.HttpEntity + +@JvmSynthetic +internal inline fun json(jsonMapper: JsonMapper, value: T): HttpRequestBody = + object : HttpRequestBody { + private val bytes: ByteArray by lazy { jsonMapper.writeValueAsBytes(value) } + + override fun writeTo(outputStream: OutputStream) = outputStream.write(bytes) + + override fun contentType(): String = "application/json" + + override fun contentLength(): Long = bytes.size.toLong() + + override fun repeatable(): Boolean = true + + override fun close() {} + } + +@JvmSynthetic +internal fun multipartFormData( + jsonMapper: JsonMapper, + fields: Map>, +): HttpRequestBody = + object : HttpRequestBody { + private val entity: HttpEntity by lazy { + MultipartEntityBuilder.create() + .apply { + fields.forEach { (name, field) -> + val knownValue = field.value.asKnown().getOrNull() + val parts = + if (knownValue is InputStream) { + // Read directly from the `InputStream` instead of reading it all + // into memory due to the `jsonMapper` serialization below. + sequenceOf(name to knownValue) + } else { + val node = jsonMapper.valueToTree(field.value) + serializePart(name, node) + } + + parts.forEach { (name, bytes) -> + addBinaryBody( + name, + bytes, + ContentType.parseLenient(field.contentType), + field.filename().getOrNull(), + ) + } + } + } + .build() + } + + private fun serializePart( + name: String, + node: JsonNode, + ): Sequence> = + when (node.nodeType) { + JsonNodeType.MISSING, + JsonNodeType.NULL -> emptySequence() + JsonNodeType.BINARY -> sequenceOf(name to node.binaryValue().inputStream()) + JsonNodeType.STRING -> sequenceOf(name to node.textValue().inputStream()) + JsonNodeType.BOOLEAN -> + sequenceOf(name to node.booleanValue().toString().inputStream()) + JsonNodeType.NUMBER -> + sequenceOf(name to node.numberValue().toString().inputStream()) + JsonNodeType.ARRAY -> + sequenceOf( + name to + node + .elements() + .asSequence() + .mapNotNull { element -> + when (element.nodeType) { + JsonNodeType.MISSING, + JsonNodeType.NULL -> null + JsonNodeType.STRING -> node.textValue() + JsonNodeType.BOOLEAN -> node.booleanValue().toString() + JsonNodeType.NUMBER -> node.numberValue().toString() + null, + JsonNodeType.BINARY, + JsonNodeType.ARRAY, + JsonNodeType.OBJECT, + JsonNodeType.POJO -> + throw StagehandInvalidDataException( + "Unexpected JsonNode type in array: ${node.nodeType}" + ) + } + } + .joinToString(",") + .inputStream() + ) + JsonNodeType.OBJECT -> + node.fields().asSequence().flatMap { (key, value) -> + serializePart("$name[$key]", value) + } + JsonNodeType.POJO, + null -> + throw StagehandInvalidDataException( + "Unexpected JsonNode type: ${node.nodeType}" + ) + } + + private fun String.inputStream(): InputStream = toByteArray().inputStream() + + override fun writeTo(outputStream: OutputStream) = entity.writeTo(outputStream) + + override fun contentType(): String = entity.contentType + + override fun contentLength(): Long = entity.contentLength + + override fun repeatable(): Boolean = entity.isRepeatable + + override fun close() = entity.close() + } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt new file mode 100644 index 0000000..2b3f90a --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt @@ -0,0 +1,25 @@ +package com.stagehand.api.core.http + +import java.io.OutputStream +import java.lang.AutoCloseable + +interface HttpRequestBody : AutoCloseable { + + fun writeTo(outputStream: OutputStream) + + fun contentType(): String? + + fun contentLength(): Long + + /** + * Determines if a request can be repeated in a meaningful way, for example before doing a + * retry. + * + * The most typical case when a request can't be retried is if the request body is being + * streamed. In this case the body data isn't available on subsequent attempts. + */ + fun repeatable(): Boolean + + /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */ + override fun close() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt new file mode 100644 index 0000000..0fa2e44 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.core.http + +import java.io.InputStream + +interface HttpResponse : AutoCloseable { + + fun statusCode(): Int + + fun headers(): Headers + + fun body(): InputStream + + /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */ + override fun close() + + interface Handler { + + fun handle(response: HttpResponse): T + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt new file mode 100644 index 0000000..82b8717 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt @@ -0,0 +1,25 @@ +package com.stagehand.api.core.http + +import java.io.InputStream + +interface HttpResponseFor : HttpResponse { + + fun parse(): T +} + +@JvmSynthetic +internal fun HttpResponse.parseable(parse: () -> T): HttpResponseFor = + object : HttpResponseFor { + + private val parsed: T by lazy { parse() } + + override fun parse(): T = parsed + + override fun statusCode(): Int = this@parseable.statusCode() + + override fun headers(): Headers = this@parseable.headers() + + override fun body(): InputStream = this@parseable.body() + + override fun close() = this@parseable.close() + } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt new file mode 100644 index 0000000..11f2997 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt @@ -0,0 +1,56 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.closeWhenPhantomReachable +import com.stagehand.api.core.http.AsyncStreamResponse.Handler +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor + +/** + * A delegating wrapper around an `AsyncStreamResponse` that closes it once it's only phantom + * reachable. + * + * This class ensures the `AsyncStreamResponse` is closed even if the user forgets to close it. + */ +internal class PhantomReachableClosingAsyncStreamResponse( + private val asyncStreamResponse: AsyncStreamResponse +) : AsyncStreamResponse { + + /** + * An object used for keeping `asyncStreamResponse` open while the object is still reachable. + */ + private val reachabilityTracker = Object() + + init { + closeWhenPhantomReachable(reachabilityTracker, asyncStreamResponse::close) + } + + override fun subscribe(handler: Handler): AsyncStreamResponse = apply { + asyncStreamResponse.subscribe(TrackedHandler(handler, reachabilityTracker)) + } + + override fun subscribe(handler: Handler, executor: Executor): AsyncStreamResponse = + apply { + asyncStreamResponse.subscribe(TrackedHandler(handler, reachabilityTracker), executor) + } + + override fun onCompleteFuture(): CompletableFuture = + asyncStreamResponse.onCompleteFuture() + + override fun close() = asyncStreamResponse.close() +} + +/** + * A wrapper around a `Handler` that also references a `reachabilityTracker` object. + * + * Referencing the `reachabilityTracker` object prevents it from getting reclaimed while the handler + * is still reachable. + */ +private class TrackedHandler( + private val handler: Handler, + private val reachabilityTracker: Any, +) : Handler { + override fun onNext(value: T) = handler.onNext(value) + + override fun onComplete(error: Optional) = handler.onComplete(error) +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt new file mode 100644 index 0000000..52da985 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt @@ -0,0 +1,26 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.closeWhenPhantomReachable +import java.util.concurrent.CompletableFuture + +/** + * A delegating wrapper around an `HttpClient` that closes it once it's only phantom reachable. + * + * This class ensures the `HttpClient` is closed even if the user forgets to close it. + */ +internal class PhantomReachableClosingHttpClient(private val httpClient: HttpClient) : HttpClient { + init { + closeWhenPhantomReachable(this, httpClient) + } + + override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse = + httpClient.execute(request, requestOptions) + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture = httpClient.executeAsync(request, requestOptions) + + override fun close() = httpClient.close() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt new file mode 100644 index 0000000..b2f75a4 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt @@ -0,0 +1,21 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.closeWhenPhantomReachable +import java.util.stream.Stream + +/** + * A delegating wrapper around a `StreamResponse` that closes it once it's only phantom reachable. + * + * This class ensures the `StreamResponse` is closed even if the user forgets to close it. + */ +internal class PhantomReachableClosingStreamResponse( + private val streamResponse: StreamResponse +) : StreamResponse { + init { + closeWhenPhantomReachable(this, streamResponse) + } + + override fun stream(): Stream = streamResponse.stream() + + override fun close() = streamResponse.close() +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt new file mode 100644 index 0000000..114b89b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt @@ -0,0 +1,129 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.core.http + +import com.stagehand.api.core.JsonArray +import com.stagehand.api.core.JsonBoolean +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonNull +import com.stagehand.api.core.JsonNumber +import com.stagehand.api.core.JsonObject +import com.stagehand.api.core.JsonString +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.toImmutable + +class QueryParams +private constructor( + private val map: Map>, + @get:JvmName("size") val size: Int, +) { + + fun isEmpty(): Boolean = map.isEmpty() + + fun keys(): Set = map.keys + + fun values(key: String): List = map[key].orEmpty() + + fun toBuilder(): Builder = Builder().putAll(map) + + companion object { + + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + + private val map: MutableMap> = mutableMapOf() + private var size: Int = 0 + + fun put(key: String, value: JsonValue): Builder = apply { + when (value) { + is JsonMissing, + is JsonNull -> {} + is JsonBoolean -> put(key, value.value.toString()) + is JsonNumber -> put(key, value.value.toString()) + is JsonString -> put(key, value.value) + is JsonArray -> + put( + key, + value.values + .asSequence() + .mapNotNull { + when (it) { + is JsonMissing, + is JsonNull -> null + is JsonBoolean -> it.value.toString() + is JsonNumber -> it.value.toString() + is JsonString -> it.value + is JsonArray, + is JsonObject -> + throw IllegalArgumentException( + "Cannot comma separate non-primitives in query params" + ) + } + } + .joinToString(","), + ) + is JsonObject -> + value.values.forEach { (nestedKey, value) -> put("$key[$nestedKey]", value) } + } + } + + fun put(key: String, value: String) = apply { + map.getOrPut(key) { mutableListOf() }.add(value) + size++ + } + + fun put(key: String, values: Iterable) = apply { values.forEach { put(key, it) } } + + fun putAll(queryParams: Map>) = apply { + queryParams.forEach(::put) + } + + fun putAll(queryParams: QueryParams) = apply { + queryParams.keys().forEach { put(it, queryParams.values(it)) } + } + + fun replace(key: String, value: String) = apply { + remove(key) + put(key, value) + } + + fun replace(key: String, values: Iterable) = apply { + remove(key) + put(key, values) + } + + fun replaceAll(queryParams: Map>) = apply { + queryParams.forEach(::replace) + } + + fun replaceAll(queryParams: QueryParams) = apply { + queryParams.keys().forEach { replace(it, queryParams.values(it)) } + } + + fun remove(key: String) = apply { size -= map.remove(key).orEmpty().size } + + fun removeAll(keys: Set) = apply { keys.forEach(::remove) } + + fun clear() = apply { + map.clear() + size = 0 + } + + fun build() = + QueryParams(map.mapValues { (_, values) -> values.toImmutable() }.toImmutable(), size) + } + + override fun hashCode(): Int = map.hashCode() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is QueryParams && map == other.map + } + + override fun toString(): String = "QueryParams{map=$map}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt new file mode 100644 index 0000000..c23a398 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt @@ -0,0 +1,265 @@ +package com.stagehand.api.core.http + +import com.stagehand.api.core.DefaultSleeper +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.Sleeper +import com.stagehand.api.core.checkRequired +import com.stagehand.api.errors.StagehandIoException +import com.stagehand.api.errors.StagehandRetryableException +import java.io.IOException +import java.time.Clock +import java.time.Duration +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException +import java.time.temporal.ChronoUnit +import java.util.UUID +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ThreadLocalRandom +import java.util.concurrent.TimeUnit +import java.util.function.Function +import kotlin.math.min +import kotlin.math.pow + +class RetryingHttpClient +private constructor( + private val httpClient: HttpClient, + private val sleeper: Sleeper, + private val clock: Clock, + private val maxRetries: Int, + private val idempotencyHeader: String?, +) : HttpClient { + + override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { + if (!isRetryable(request) || maxRetries <= 0) { + return httpClient.execute(request, requestOptions) + } + + var modifiedRequest = maybeAddIdempotencyHeader(request) + + // Don't send the current retry count in the headers if the caller set their own value. + val shouldSendRetryCount = + !modifiedRequest.headers.names().contains("X-Stainless-Retry-Count") + + var retries = 0 + + while (true) { + if (shouldSendRetryCount) { + modifiedRequest = setRetryCountHeader(modifiedRequest, retries) + } + + val response = + try { + val response = httpClient.execute(modifiedRequest, requestOptions) + if (++retries > maxRetries || !shouldRetry(response)) { + return response + } + + response + } catch (throwable: Throwable) { + if (++retries > maxRetries || !shouldRetry(throwable)) { + throw throwable + } + + null + } + + val backoffDuration = getRetryBackoffDuration(retries, response) + // All responses must be closed, so close the failed one before retrying. + response?.close() + sleeper.sleep(backoffDuration) + } + } + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture { + if (!isRetryable(request) || maxRetries <= 0) { + return httpClient.executeAsync(request, requestOptions) + } + + val modifiedRequest = maybeAddIdempotencyHeader(request) + + // Don't send the current retry count in the headers if the caller set their own value. + val shouldSendRetryCount = + !modifiedRequest.headers.names().contains("X-Stainless-Retry-Count") + + var retries = 0 + + fun executeWithRetries( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture { + val requestWithRetryCount = + if (shouldSendRetryCount) setRetryCountHeader(request, retries) else request + + return httpClient + .executeAsync(requestWithRetryCount, requestOptions) + .handleAsync( + fun( + response: HttpResponse?, + throwable: Throwable?, + ): CompletableFuture { + if (response != null) { + if (++retries > maxRetries || !shouldRetry(response)) { + return CompletableFuture.completedFuture(response) + } + } else { + if (++retries > maxRetries || !shouldRetry(throwable!!)) { + val failedFuture = CompletableFuture() + failedFuture.completeExceptionally(throwable) + return failedFuture + } + } + + val backoffDuration = getRetryBackoffDuration(retries, response) + // All responses must be closed, so close the failed one before retrying. + response?.close() + return sleeper.sleepAsync(backoffDuration).thenCompose { + executeWithRetries(requestWithRetryCount, requestOptions) + } + } + ) { + // Run in the same thread. + it.run() + } + .thenCompose(Function.identity()) + } + + return executeWithRetries(modifiedRequest, requestOptions) + } + + override fun close() { + httpClient.close() + sleeper.close() + } + + private fun isRetryable(request: HttpRequest): Boolean = + // Some requests, such as when a request body is being streamed, cannot be retried because + // the body data aren't available on subsequent attempts. + request.body?.repeatable() ?: true + + private fun setRetryCountHeader(request: HttpRequest, retries: Int): HttpRequest = + request.toBuilder().replaceHeaders("X-Stainless-Retry-Count", retries.toString()).build() + + private fun idempotencyKey(): String = "stainless-java-retry-${UUID.randomUUID()}" + + private fun maybeAddIdempotencyHeader(request: HttpRequest): HttpRequest { + if (idempotencyHeader == null || request.headers.names().contains(idempotencyHeader)) { + return request + } + + return request + .toBuilder() + // Set a header to uniquely identify the request when retried. + .putHeader(idempotencyHeader, idempotencyKey()) + .build() + } + + private fun shouldRetry(response: HttpResponse): Boolean { + // Note: this is not a standard header + val shouldRetryHeader = response.headers().values("X-Should-Retry").getOrNull(0) + val statusCode = response.statusCode() + + return when { + // If the server explicitly says whether to retry, obey + shouldRetryHeader == "true" -> true + shouldRetryHeader == "false" -> false + + // Retry on request timeouts + statusCode == 408 -> true + // Retry on lock timeouts + statusCode == 409 -> true + // Retry on rate limits + statusCode == 429 -> true + // Retry internal errors + statusCode >= 500 -> true + else -> false + } + } + + private fun shouldRetry(throwable: Throwable): Boolean = + // Only retry known retryable exceptions, other exceptions are not intended to be retried. + throwable is IOException || + throwable is StagehandIoException || + throwable is StagehandRetryableException + + private fun getRetryBackoffDuration(retries: Int, response: HttpResponse?): Duration { + // About the Retry-After header: + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After + response + ?.headers() + ?.let { headers -> + headers + .values("Retry-After-Ms") + .getOrNull(0) + ?.toFloatOrNull() + ?.times(TimeUnit.MILLISECONDS.toNanos(1)) + ?: headers.values("Retry-After").getOrNull(0)?.let { retryAfter -> + retryAfter.toFloatOrNull()?.times(TimeUnit.SECONDS.toNanos(1)) + ?: try { + ChronoUnit.MILLIS.between( + OffsetDateTime.now(clock), + OffsetDateTime.parse( + retryAfter, + DateTimeFormatter.RFC_1123_DATE_TIME, + ), + ) + } catch (e: DateTimeParseException) { + null + } + } + } + ?.let { retryAfterNanos -> + // If the API asks us to wait a certain amount of time (and it's a reasonable + // amount), just + // do what it says. + val retryAfter = Duration.ofNanos(retryAfterNanos.toLong()) + if (retryAfter in Duration.ofNanos(0)..Duration.ofMinutes(1)) { + return retryAfter + } + } + + // Apply exponential backoff, but not more than the max. + val backoffSeconds = min(0.5 * 2.0.pow(retries - 1), 8.0) + + // Apply some jitter + val jitter = 1.0 - 0.25 * ThreadLocalRandom.current().nextDouble() + + return Duration.ofNanos((TimeUnit.SECONDS.toNanos(1) * backoffSeconds * jitter).toLong()) + } + + companion object { + + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + + private var httpClient: HttpClient? = null + private var sleeper: Sleeper? = null + private var clock: Clock = Clock.systemUTC() + private var maxRetries: Int = 2 + private var idempotencyHeader: String? = null + + fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient } + + fun sleeper(sleeper: Sleeper) = apply { this.sleeper = sleeper } + + fun clock(clock: Clock) = apply { this.clock = clock } + + fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } + + fun idempotencyHeader(header: String) = apply { this.idempotencyHeader = header } + + fun build(): HttpClient = + RetryingHttpClient( + checkRequired("httpClient", httpClient), + sleeper ?: DefaultSleeper(), + clock, + maxRetries, + idempotencyHeader, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt new file mode 100644 index 0000000..ace181d --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt @@ -0,0 +1,19 @@ +package com.stagehand.api.core.http + +import java.util.stream.Stream + +interface StreamResponse : AutoCloseable { + + fun stream(): Stream + + /** Overridden from [AutoCloseable] to not have a checked exception in its signature. */ + override fun close() +} + +@JvmSynthetic +internal fun StreamResponse.map(transform: (T) -> R): StreamResponse = + object : StreamResponse { + override fun stream(): Stream = this@map.stream().map(transform) + + override fun close() = this@map.close() + } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt new file mode 100644 index 0000000..3e34a60 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt @@ -0,0 +1,80 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class BadRequestException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + StagehandServiceException("400: $body", cause) { + + override fun statusCode(): Int = 400 + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [BadRequestException]. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BadRequestException]. */ + class Builder internal constructor() { + + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(badRequestException: BadRequestException) = apply { + headers = badRequestException.headers + body = badRequestException.body + cause = badRequestException.cause + } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [BadRequestException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BadRequestException = + BadRequestException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt new file mode 100644 index 0000000..e44477e --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt @@ -0,0 +1,91 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class InternalServerException +private constructor( + private val statusCode: Int, + private val headers: Headers, + private val body: JsonValue, + cause: Throwable?, +) : StagehandServiceException("$statusCode: $body", cause) { + + override fun statusCode(): Int = statusCode + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [InternalServerException]. + * + * The following fields are required: + * ```java + * .statusCode() + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [InternalServerException]. */ + class Builder internal constructor() { + + private var statusCode: Int? = null + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(internalServerException: InternalServerException) = apply { + statusCode = internalServerException.statusCode + headers = internalServerException.headers + body = internalServerException.body + cause = internalServerException.cause + } + + fun statusCode(statusCode: Int) = apply { this.statusCode = statusCode } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [InternalServerException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .statusCode() + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): InternalServerException = + InternalServerException( + checkRequired("statusCode", statusCode), + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt new file mode 100644 index 0000000..55d282f --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt @@ -0,0 +1,76 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class NotFoundException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + StagehandServiceException("404: $body", cause) { + + override fun statusCode(): Int = 404 + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [NotFoundException]. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [NotFoundException]. */ + class Builder internal constructor() { + + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(notFoundException: NotFoundException) = apply { + headers = notFoundException.headers + body = notFoundException.body + cause = notFoundException.cause + } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [NotFoundException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): NotFoundException = + NotFoundException(checkRequired("headers", headers), checkRequired("body", body), cause) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt new file mode 100644 index 0000000..f79f40a --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt @@ -0,0 +1,80 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class PermissionDeniedException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + StagehandServiceException("403: $body", cause) { + + override fun statusCode(): Int = 403 + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [PermissionDeniedException]. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PermissionDeniedException]. */ + class Builder internal constructor() { + + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(permissionDeniedException: PermissionDeniedException) = apply { + headers = permissionDeniedException.headers + body = permissionDeniedException.body + cause = permissionDeniedException.cause + } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [PermissionDeniedException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PermissionDeniedException = + PermissionDeniedException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt new file mode 100644 index 0000000..1119740 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt @@ -0,0 +1,80 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class RateLimitException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + StagehandServiceException("429: $body", cause) { + + override fun statusCode(): Int = 429 + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RateLimitException]. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [RateLimitException]. */ + class Builder internal constructor() { + + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(rateLimitException: RateLimitException) = apply { + headers = rateLimitException.headers + body = rateLimitException.body + cause = rateLimitException.cause + } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [RateLimitException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RateLimitException = + RateLimitException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt new file mode 100644 index 0000000..0d0087f --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt @@ -0,0 +1,5 @@ +package com.stagehand.api.errors + +open class StagehandException +@JvmOverloads +constructor(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt new file mode 100644 index 0000000..3d7fb03 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt @@ -0,0 +1,5 @@ +package com.stagehand.api.errors + +class StagehandInvalidDataException +@JvmOverloads +constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt new file mode 100644 index 0000000..4080af1 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt @@ -0,0 +1,5 @@ +package com.stagehand.api.errors + +class StagehandIoException +@JvmOverloads +constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt new file mode 100644 index 0000000..252b6c6 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt @@ -0,0 +1,14 @@ +package com.stagehand.api.errors + +/** + * Exception that indicates a transient error that can be retried. + * + * When this exception is thrown during an HTTP request, the SDK will automatically retry the + * request up to the maximum number of retries. + * + * @param message A descriptive error message + * @param cause The underlying cause of this exception, if any + */ +class StagehandRetryableException +@JvmOverloads +constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt new file mode 100644 index 0000000..af4ad3b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt @@ -0,0 +1,17 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.http.Headers + +abstract class StagehandServiceException +protected constructor(message: String, cause: Throwable? = null) : + StagehandException(message, cause) { + + abstract fun statusCode(): Int + + abstract fun headers(): Headers + + abstract fun body(): JsonValue +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt new file mode 100644 index 0000000..d3fa413 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt @@ -0,0 +1,80 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class UnauthorizedException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + StagehandServiceException("401: $body", cause) { + + override fun statusCode(): Int = 401 + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [UnauthorizedException]. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UnauthorizedException]. */ + class Builder internal constructor() { + + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(unauthorizedException: UnauthorizedException) = apply { + headers = unauthorizedException.headers + body = unauthorizedException.body + cause = unauthorizedException.cause + } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [UnauthorizedException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnauthorizedException = + UnauthorizedException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt new file mode 100644 index 0000000..042ec74 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt @@ -0,0 +1,92 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class UnexpectedStatusCodeException +private constructor( + private val statusCode: Int, + private val headers: Headers, + private val body: JsonValue, + cause: Throwable?, +) : StagehandServiceException("$statusCode: $body", cause) { + + override fun statusCode(): Int = statusCode + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [UnexpectedStatusCodeException]. + * + * The following fields are required: + * ```java + * .statusCode() + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UnexpectedStatusCodeException]. */ + class Builder internal constructor() { + + private var statusCode: Int? = null + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(unexpectedStatusCodeException: UnexpectedStatusCodeException) = apply { + statusCode = unexpectedStatusCodeException.statusCode + headers = unexpectedStatusCodeException.headers + body = unexpectedStatusCodeException.body + cause = unexpectedStatusCodeException.cause + } + + fun statusCode(statusCode: Int) = apply { this.statusCode = statusCode } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [UnexpectedStatusCodeException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .statusCode() + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnexpectedStatusCodeException = + UnexpectedStatusCodeException( + checkRequired("statusCode", statusCode), + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt new file mode 100644 index 0000000..eb3482b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt @@ -0,0 +1,80 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.errors + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class UnprocessableEntityException +private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : + StagehandServiceException("422: $body", cause) { + + override fun statusCode(): Int = 422 + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [UnprocessableEntityException]. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UnprocessableEntityException]. */ + class Builder internal constructor() { + + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(unprocessableEntityException: UnprocessableEntityException) = apply { + headers = unprocessableEntityException.headers + body = unprocessableEntityException.body + cause = unprocessableEntityException.cause + } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [UnprocessableEntityException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnprocessableEntityException = + UnprocessableEntityException( + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt new file mode 100644 index 0000000..3d159b8 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt @@ -0,0 +1,350 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkKnown +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.toImmutable +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class Action +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val arguments: JsonField>, + private val description: JsonField, + private val method: JsonField, + private val selector: JsonField, + private val backendNodeId: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField> = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), + @JsonProperty("selector") @ExcludeMissing selector: JsonField = JsonMissing.of(), + @JsonProperty("backendNodeId") + @ExcludeMissing + backendNodeId: JsonField = JsonMissing.of(), + ) : this(arguments, description, method, selector, backendNodeId, mutableMapOf()) + + /** + * Arguments for the method + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun arguments(): List = arguments.getRequired("arguments") + + /** + * Human-readable description of the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun description(): String = description.getRequired("description") + + /** + * Method to execute (e.g., "click", "fill") + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun method(): String = method.getRequired("method") + + /** + * CSS or XPath selector for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun selector(): String = selector.getRequired("selector") + + /** + * CDP backend node ID + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") + + /** + * Returns the raw JSON value of [arguments]. + * + * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("arguments") @ExcludeMissing fun _arguments(): JsonField> = arguments + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("description") @ExcludeMissing fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [method]. + * + * Unlike [method], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [backendNodeId]. + * + * Unlike [backendNodeId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("backendNodeId") + @ExcludeMissing + fun _backendNodeId(): JsonField = backendNodeId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Action]. + * + * The following fields are required: + * ```java + * .arguments() + * .description() + * .method() + * .selector() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Action]. */ + class Builder internal constructor() { + + private var arguments: JsonField>? = null + private var description: JsonField? = null + private var method: JsonField? = null + private var selector: JsonField? = null + private var backendNodeId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(action: Action) = apply { + arguments = action.arguments.map { it.toMutableList() } + description = action.description + method = action.method + selector = action.selector + backendNodeId = action.backendNodeId + additionalProperties = action.additionalProperties.toMutableMap() + } + + /** Arguments for the method */ + fun arguments(arguments: List) = arguments(JsonField.of(arguments)) + + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun arguments(arguments: JsonField>) = apply { + this.arguments = arguments.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [arguments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addArgument(argument: String) = apply { + arguments = + (arguments ?: JsonField.of(mutableListOf())).also { + checkKnown("arguments", it).add(argument) + } + } + + /** Human-readable description of the action */ + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun description(description: JsonField) = apply { this.description = description } + + /** Method to execute (e.g., "click", "fill") */ + fun method(method: String) = method(JsonField.of(method)) + + /** + * Sets [Builder.method] to an arbitrary JSON value. + * + * You should usually call [Builder.method] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun method(method: JsonField) = apply { this.method = method } + + /** CSS or XPath selector for the element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** CDP backend node ID */ + fun backendNodeId(backendNodeId: Long) = backendNodeId(JsonField.of(backendNodeId)) + + /** + * Sets [Builder.backendNodeId] to an arbitrary JSON value. + * + * You should usually call [Builder.backendNodeId] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun backendNodeId(backendNodeId: JsonField) = apply { + this.backendNodeId = backendNodeId + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Action]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .arguments() + * .description() + * .method() + * .selector() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Action = + Action( + checkRequired("arguments", arguments).map { it.toImmutable() }, + checkRequired("description", description), + checkRequired("method", method), + checkRequired("selector", selector), + backendNodeId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Action = apply { + if (validated) { + return@apply + } + + arguments() + description() + method() + selector() + backendNodeId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (arguments.asKnown().getOrNull()?.size ?: 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (method.asKnown().isPresent) 1 else 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (if (backendNodeId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Action && + arguments == other.arguments && + description == other.description && + method == other.method && + selector == other.selector && + backendNodeId == other.backendNodeId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(arguments, description, method, selector, backendNodeId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Action{arguments=$arguments, description=$description, method=$method, selector=$selector, backendNodeId=$backendNodeId, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt new file mode 100644 index 0000000..577bfbd --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt @@ -0,0 +1,392 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class ModelConfig +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val apiKey: JsonField, + private val baseUrl: JsonField, + private val model: JsonField, + private val provider: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), + @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), + ) : this(apiKey, baseUrl, model, provider, mutableMapOf()) + + /** + * API key for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun apiKey(): Optional = apiKey.getOptional("apiKey") + + /** + * Custom base URL for API + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + + /** + * Model name + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun provider(): Optional = provider.getOptional("provider") + + /** + * Returns the raw JSON value of [apiKey]. + * + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + + /** + * Returns the raw JSON value of [baseUrl]. + * + * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [provider]. + * + * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [ModelConfig]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ModelConfig]. */ + class Builder internal constructor() { + + private var apiKey: JsonField = JsonMissing.of() + private var baseUrl: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() + private var provider: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(modelConfig: ModelConfig) = apply { + apiKey = modelConfig.apiKey + baseUrl = modelConfig.baseUrl + model = modelConfig.model + provider = modelConfig.provider + additionalProperties = modelConfig.additionalProperties.toMutableMap() + } + + /** API key for the model provider */ + fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + + /** + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + + /** Custom base URL for API */ + fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) + + /** + * Sets [Builder.baseUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.baseUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + + /** Model name */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + fun provider(provider: Provider) = provider(JsonField.of(provider)) + + /** + * Sets [Builder.provider] to an arbitrary JSON value. + * + * You should usually call [Builder.provider] with a well-typed [Provider] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun provider(provider: JsonField) = apply { this.provider = provider } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ModelConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ModelConfig = + ModelConfig(apiKey, baseUrl, model, provider, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): ModelConfig = apply { + if (validated) { + return@apply + } + + apiKey() + baseUrl() + model() + provider().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (apiKey.asKnown().isPresent) 1 else 0) + + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (if (model.asKnown().isPresent) 1 else 0) + + (provider.asKnown().getOrNull()?.validity() ?: 0) + + class Provider @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPENAI = of("openai") + + @JvmField val ANTHROPIC = of("anthropic") + + @JvmField val GOOGLE = of("google") + + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) + } + + /** An enum containing [Provider]'s known values. */ + enum class Known { + OPENAI, + ANTHROPIC, + GOOGLE, + } + + /** + * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Provider] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPENAI, + ANTHROPIC, + GOOGLE, + /** An enum member indicating that [Provider] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPENAI -> Value.OPENAI + ANTHROPIC -> Value.ANTHROPIC + GOOGLE -> Value.GOOGLE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + OPENAI -> Known.OPENAI + ANTHROPIC -> Known.ANTHROPIC + GOOGLE -> Known.GOOGLE + else -> throw StagehandInvalidDataException("Unknown Provider: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Provider = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Provider && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ModelConfig && + apiKey == other.apiKey && + baseUrl == other.baseUrl && + model == other.model && + provider == other.provider && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(apiKey, baseUrl, model, provider, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ModelConfig{apiKey=$apiKey, baseUrl=$baseUrl, model=$model, provider=$provider, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt new file mode 100644 index 0000000..8631b64 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt @@ -0,0 +1,1233 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.BaseDeserializer +import com.stagehand.api.core.BaseSerializer +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.allMaxBy +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.getOrThrow +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.core.toImmutable +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Performs a browser action based on natural language instruction or a specific action object + * returned by observe(). + */ +class SessionActParams +private constructor( + private val sessionId: String?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun sessionId(): Optional = Optional.ofNullable(sessionId) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** + * Natural language instruction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun input(): Input = body.input() + + /** + * Frame ID to act on (optional) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _input(): JsonField = body._input() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionActParams]. + * + * The following fields are required: + * ```java + * .input() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionActParams]. */ + class Builder internal constructor() { + + private var sessionId: String? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionActParams: SessionActParams) = apply { + sessionId = sessionActParams.sessionId + xStreamResponse = sessionActParams.xStreamResponse + body = sessionActParams.body.toBuilder() + additionalHeaders = sessionActParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionActParams.additionalQueryParams.toBuilder() + } + + fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } + + /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ + fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) + + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [input] + * - [frameId] + * - [options] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Natural language instruction */ + fun input(input: Input) = apply { body.input(input) } + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [Input] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField) = apply { body.input(input) } + + /** Alias for calling [input] with `Input.ofString(string)`. */ + fun input(string: String) = apply { body.input(string) } + + /** Alias for calling [input] with `Input.ofAction(action)`. */ + fun input(action: Action) = apply { body.input(action) } + + /** Frame ID to act on (optional) */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionActParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionActParams = + SessionActParams( + sessionId, + xStreamResponse, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> sessionId ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val input: JsonField, + private val frameId: JsonField, + private val options: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + ) : this(input, frameId, options, mutableMapOf()) + + /** + * Natural language instruction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun input(): Input = input.getRequired("input") + + /** + * Frame ID to act on (optional) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .input() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var input: JsonField? = null + private var frameId: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + input = body.input + frameId = body.frameId + options = body.options + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Natural language instruction */ + fun input(input: Input) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [Input] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun input(input: JsonField) = apply { this.input = input } + + /** Alias for calling [input] with `Input.ofString(string)`. */ + fun input(string: String) = input(Input.ofString(string)) + + /** Alias for calling [input] with `Input.ofAction(action)`. */ + fun input(action: Action) = input(Input.ofAction(action)) + + /** Frame ID to act on (optional) */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("input", input), + frameId, + options, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + input().validate() + frameId() + options().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (input.asKnown().getOrNull()?.validity() ?: 0) + + (if (frameId.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + input == other.input && + frameId == other.frameId && + options == other.options && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(input, frameId, options, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{input=$input, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" + } + + /** Natural language instruction */ + @JsonDeserialize(using = Input.Deserializer::class) + @JsonSerialize(using = Input.Serializer::class) + class Input + private constructor( + private val string: String? = null, + private val action: Action? = null, + private val _json: JsonValue? = null, + ) { + + /** Natural language instruction */ + fun string(): Optional = Optional.ofNullable(string) + + fun action(): Optional = Optional.ofNullable(action) + + fun isString(): Boolean = string != null + + fun isAction(): Boolean = action != null + + /** Natural language instruction */ + fun asString(): String = string.getOrThrow("string") + + fun asAction(): Action = action.getOrThrow("action") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + action != null -> visitor.visitAction(action) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Input = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitAction(action: Action) { + action.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitString(string: String) = 1 + + override fun visitAction(action: Action) = action.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Input && string == other.string && action == other.action + } + + override fun hashCode(): Int = Objects.hash(string, action) + + override fun toString(): String = + when { + string != null -> "Input{string=$string}" + action != null -> "Input{action=$action}" + _json != null -> "Input{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Input") + } + + companion object { + + /** Natural language instruction */ + @JvmStatic fun ofString(string: String) = Input(string = string) + + @JvmStatic fun ofAction(action: Action) = Input(action = action) + } + + /** An interface that defines how to map each variant of [Input] to a value of type [T]. */ + interface Visitor { + + /** Natural language instruction */ + fun visitString(string: String): T + + fun visitAction(action: Action): T + + /** + * Maps an unknown variant of [Input] to a value of type [T]. + * + * An instance of [Input] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Input: $json") + } + } + + internal class Deserializer : BaseDeserializer(Input::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Input { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Input(action = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Input(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from array). + 0 -> Input(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Input::class) { + + override fun serialize( + value: Input, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.action != null -> generator.writeObject(value.action) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Input") + } + } + } + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val timeout: JsonField, + private val variables: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + @JsonProperty("variables") + @ExcludeMissing + variables: JsonField = JsonMissing.of(), + ) : this(model, timeout, variables, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Timeout in milliseconds + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * Template variables for instruction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun variables(): Optional = variables.getOptional("variables") + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + /** + * Returns the raw JSON value of [variables]. + * + * Unlike [variables], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("variables") + @ExcludeMissing + fun _variables(): JsonField = variables + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var variables: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + model = options.model + timeout = options.timeout + variables = options.variables + additionalProperties = options.additionalProperties.toMutableMap() + } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Timeout in milliseconds */ + fun timeout(timeout: Long) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + /** Template variables for instruction */ + fun variables(variables: Variables) = variables(JsonField.of(variables)) + + /** + * Sets [Builder.variables] to an arbitrary JSON value. + * + * You should usually call [Builder.variables] with a well-typed [Variables] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun variables(variables: JsonField) = apply { this.variables = variables } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(model, timeout, variables, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + model().ifPresent { it.validate() } + timeout() + variables().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + (variables.asKnown().getOrNull()?.validity() ?: 0) + + /** Template variables for instruction */ + class Variables + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Variables]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Variables]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(variables: Variables) = apply { + additionalProperties = variables.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Variables]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Variables = Variables(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Variables = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Variables && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Variables{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + model == other.model && + timeout == other.timeout && + variables == other.variables && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, timeout, variables, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{model=$model, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" + } + + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionActParams && + sessionId == other.sessionId && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionActParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt new file mode 100644 index 0000000..dca978d --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt @@ -0,0 +1,269 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkKnown +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.toImmutable +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import kotlin.jvm.optionals.getOrNull + +class SessionActResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val actions: JsonField>, + private val message: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("actions") + @ExcludeMissing + actions: JsonField> = JsonMissing.of(), + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(actions, message, success, mutableMapOf()) + + /** + * Actions that were executed + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun actions(): List = actions.getRequired("actions") + + /** + * Result message + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun message(): String = message.getRequired("message") + + /** + * Whether the action succeeded + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Boolean = success.getRequired("success") + + /** + * Returns the raw JSON value of [actions]. + * + * Unlike [actions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actions") @ExcludeMissing fun _actions(): JsonField> = actions + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionActResponse]. + * + * The following fields are required: + * ```java + * .actions() + * .message() + * .success() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionActResponse]. */ + class Builder internal constructor() { + + private var actions: JsonField>? = null + private var message: JsonField? = null + private var success: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionActResponse: SessionActResponse) = apply { + actions = sessionActResponse.actions.map { it.toMutableList() } + message = sessionActResponse.message + success = sessionActResponse.success + additionalProperties = sessionActResponse.additionalProperties.toMutableMap() + } + + /** Actions that were executed */ + fun actions(actions: List) = actions(JsonField.of(actions)) + + /** + * Sets [Builder.actions] to an arbitrary JSON value. + * + * You should usually call [Builder.actions] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun actions(actions: JsonField>) = apply { + this.actions = actions.map { it.toMutableList() } + } + + /** + * Adds a single [Action] to [actions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAction(action: Action) = apply { + actions = + (actions ?: JsonField.of(mutableListOf())).also { + checkKnown("actions", it).add(action) + } + } + + /** Result message */ + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** Whether the action succeeded */ + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionActResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .actions() + * .message() + * .success() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionActResponse = + SessionActResponse( + checkRequired("actions", actions).map { it.toImmutable() }, + checkRequired("message", message), + checkRequired("success", success), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SessionActResponse = apply { + if (validated) { + return@apply + } + + actions().forEach { it.validate() } + message() + success() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (message.asKnown().isPresent) 1 else 0) + + (if (success.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionActResponse && + actions == other.actions && + message == other.message && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(actions, message, success, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionActResponse{actions=$actions, message=$message, success=$success, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt new file mode 100644 index 0000000..c559008 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt @@ -0,0 +1,229 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Closes the browser and cleans up all resources associated with the session. */ +class SessionEndParams +private constructor( + private val sessionId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun sessionId(): Optional = Optional.ofNullable(sessionId) + + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionEndParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionEndParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionEndParams]. */ + class Builder internal constructor() { + + private var sessionId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionEndParams: SessionEndParams) = apply { + sessionId = sessionEndParams.sessionId + additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionEndParams.additionalQueryParams.toBuilder() + additionalBodyProperties = sessionEndParams.additionalBodyProperties.toMutableMap() + } + + fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } + + /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ + fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [SessionEndParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionEndParams = + SessionEndParams( + sessionId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> sessionId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionEndParams && + sessionId == other.sessionId && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash(sessionId, additionalHeaders, additionalQueryParams, additionalBodyProperties) + + override fun toString() = + "SessionEndParams{sessionId=$sessionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt new file mode 100644 index 0000000..3a162e7 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt @@ -0,0 +1,153 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional + +class SessionEndResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val success: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of() + ) : this(success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun success(): Optional = success.getOptional("success") + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionEndResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionEndResponse]. */ + class Builder internal constructor() { + + private var success: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionEndResponse: SessionEndResponse) = apply { + success = sessionEndResponse.success + additionalProperties = sessionEndResponse.additionalProperties.toMutableMap() + } + + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionEndResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionEndResponse = + SessionEndResponse(success, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionEndResponse = apply { + if (validated) { + return@apply + } + + success() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (if (success.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionEndResponse && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(success, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionEndResponse{success=$success, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt new file mode 100644 index 0000000..5d77b26 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt @@ -0,0 +1,1547 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.BaseDeserializer +import com.stagehand.api.core.BaseSerializer +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.allMaxBy +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.getOrThrow +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Runs an autonomous agent that can perform multiple actions to complete a complex task. */ +class SessionExecuteAgentParams +private constructor( + private val sessionId: String?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun sessionId(): Optional = Optional.ofNullable(sessionId) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun agentConfig(): AgentConfig = body.agentConfig() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun executeOptions(): ExecuteOptions = body.executeOptions() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * Returns the raw JSON value of [agentConfig]. + * + * Unlike [agentConfig], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _agentConfig(): JsonField = body._agentConfig() + + /** + * Returns the raw JSON value of [executeOptions]. + * + * Unlike [executeOptions], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _executeOptions(): JsonField = body._executeOptions() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionExecuteAgentParams]. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExecuteAgentParams]. */ + class Builder internal constructor() { + + private var sessionId: String? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionExecuteAgentParams: SessionExecuteAgentParams) = apply { + sessionId = sessionExecuteAgentParams.sessionId + xStreamResponse = sessionExecuteAgentParams.xStreamResponse + body = sessionExecuteAgentParams.body.toBuilder() + additionalHeaders = sessionExecuteAgentParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionExecuteAgentParams.additionalQueryParams.toBuilder() + } + + fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } + + /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ + fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) + + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [agentConfig] + * - [executeOptions] + * - [frameId] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + fun agentConfig(agentConfig: AgentConfig) = apply { body.agentConfig(agentConfig) } + + /** + * Sets [Builder.agentConfig] to an arbitrary JSON value. + * + * You should usually call [Builder.agentConfig] with a well-typed [AgentConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun agentConfig(agentConfig: JsonField) = apply { + body.agentConfig(agentConfig) + } + + fun executeOptions(executeOptions: ExecuteOptions) = apply { + body.executeOptions(executeOptions) + } + + /** + * Sets [Builder.executeOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.executeOptions] with a well-typed [ExecuteOptions] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun executeOptions(executeOptions: JsonField) = apply { + body.executeOptions(executeOptions) + } + + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionExecuteAgentParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionExecuteAgentParams = + SessionExecuteAgentParams( + sessionId, + xStreamResponse, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> sessionId ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val agentConfig: JsonField, + private val executeOptions: JsonField, + private val frameId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("agentConfig") + @ExcludeMissing + agentConfig: JsonField = JsonMissing.of(), + @JsonProperty("executeOptions") + @ExcludeMissing + executeOptions: JsonField = JsonMissing.of(), + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + ) : this(agentConfig, executeOptions, frameId, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun agentConfig(): AgentConfig = agentConfig.getRequired("agentConfig") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun executeOptions(): ExecuteOptions = executeOptions.getRequired("executeOptions") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * Returns the raw JSON value of [agentConfig]. + * + * Unlike [agentConfig], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("agentConfig") + @ExcludeMissing + fun _agentConfig(): JsonField = agentConfig + + /** + * Returns the raw JSON value of [executeOptions]. + * + * Unlike [executeOptions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("executeOptions") + @ExcludeMissing + fun _executeOptions(): JsonField = executeOptions + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var agentConfig: JsonField? = null + private var executeOptions: JsonField? = null + private var frameId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + agentConfig = body.agentConfig + executeOptions = body.executeOptions + frameId = body.frameId + additionalProperties = body.additionalProperties.toMutableMap() + } + + fun agentConfig(agentConfig: AgentConfig) = agentConfig(JsonField.of(agentConfig)) + + /** + * Sets [Builder.agentConfig] to an arbitrary JSON value. + * + * You should usually call [Builder.agentConfig] with a well-typed [AgentConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun agentConfig(agentConfig: JsonField) = apply { + this.agentConfig = agentConfig + } + + fun executeOptions(executeOptions: ExecuteOptions) = + executeOptions(JsonField.of(executeOptions)) + + /** + * Sets [Builder.executeOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.executeOptions] with a well-typed [ExecuteOptions] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun executeOptions(executeOptions: JsonField) = apply { + this.executeOptions = executeOptions + } + + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("agentConfig", agentConfig), + checkRequired("executeOptions", executeOptions), + frameId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + agentConfig().validate() + executeOptions().validate() + frameId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (agentConfig.asKnown().getOrNull()?.validity() ?: 0) + + (executeOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (frameId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + agentConfig == other.agentConfig && + executeOptions == other.executeOptions && + frameId == other.frameId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(agentConfig, executeOptions, frameId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{agentConfig=$agentConfig, executeOptions=$executeOptions, frameId=$frameId, additionalProperties=$additionalProperties}" + } + + class AgentConfig + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cua: JsonField, + private val model: JsonField, + private val provider: JsonField, + private val systemPrompt: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("provider") + @ExcludeMissing + provider: JsonField = JsonMissing.of(), + @JsonProperty("systemPrompt") + @ExcludeMissing + systemPrompt: JsonField = JsonMissing.of(), + ) : this(cua, model, provider, systemPrompt, mutableMapOf()) + + /** + * Enable Computer Use Agent mode + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cua(): Optional = cua.getOptional("cua") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun provider(): Optional = provider.getOptional("provider") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") + + /** + * Returns the raw JSON value of [cua]. + * + * Unlike [cua], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cua") @ExcludeMissing fun _cua(): JsonField = cua + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [provider]. + * + * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + + /** + * Returns the raw JSON value of [systemPrompt]. + * + * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("systemPrompt") + @ExcludeMissing + fun _systemPrompt(): JsonField = systemPrompt + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [AgentConfig]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AgentConfig]. */ + class Builder internal constructor() { + + private var cua: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() + private var provider: JsonField = JsonMissing.of() + private var systemPrompt: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(agentConfig: AgentConfig) = apply { + cua = agentConfig.cua + model = agentConfig.model + provider = agentConfig.provider + systemPrompt = agentConfig.systemPrompt + additionalProperties = agentConfig.additionalProperties.toMutableMap() + } + + /** Enable Computer Use Agent mode */ + fun cua(cua: Boolean) = cua(JsonField.of(cua)) + + /** + * Sets [Builder.cua] to an arbitrary JSON value. + * + * You should usually call [Builder.cua] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun cua(cua: JsonField) = apply { this.cua = cua } + + fun model(model: Model) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [Model] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `Model.ofString(string)`. */ + fun model(string: String) = model(Model.ofString(string)) + + /** Alias for calling [model] with `Model.ofConfig(config)`. */ + fun model(config: ModelConfig) = model(Model.ofConfig(config)) + + fun provider(provider: Provider) = provider(JsonField.of(provider)) + + /** + * Sets [Builder.provider] to an arbitrary JSON value. + * + * You should usually call [Builder.provider] with a well-typed [Provider] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun provider(provider: JsonField) = apply { this.provider = provider } + + fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) + + /** + * Sets [Builder.systemPrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.systemPrompt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun systemPrompt(systemPrompt: JsonField) = apply { + this.systemPrompt = systemPrompt + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AgentConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AgentConfig = + AgentConfig(cua, model, provider, systemPrompt, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): AgentConfig = apply { + if (validated) { + return@apply + } + + cua() + model().ifPresent { it.validate() } + provider().ifPresent { it.validate() } + systemPrompt() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (cua.asKnown().isPresent) 1 else 0) + + (model.asKnown().getOrNull()?.validity() ?: 0) + + (provider.asKnown().getOrNull()?.validity() ?: 0) + + (if (systemPrompt.asKnown().isPresent) 1 else 0) + + @JsonDeserialize(using = Model.Deserializer::class) + @JsonSerialize(using = Model.Serializer::class) + class Model + private constructor( + private val string: String? = null, + private val config: ModelConfig? = null, + private val _json: JsonValue? = null, + ) { + + fun string(): Optional = Optional.ofNullable(string) + + fun config(): Optional = Optional.ofNullable(config) + + fun isString(): Boolean = string != null + + fun isConfig(): Boolean = config != null + + fun asString(): String = string.getOrThrow("string") + + fun asConfig(): ModelConfig = config.getOrThrow("config") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + config != null -> visitor.visitConfig(config) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Model = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitConfig(config: ModelConfig) { + config.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitString(string: String) = 1 + + override fun visitConfig(config: ModelConfig) = config.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Model && string == other.string && config == other.config + } + + override fun hashCode(): Int = Objects.hash(string, config) + + override fun toString(): String = + when { + string != null -> "Model{string=$string}" + config != null -> "Model{config=$config}" + _json != null -> "Model{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Model") + } + + companion object { + + @JvmStatic fun ofString(string: String) = Model(string = string) + + @JvmStatic fun ofConfig(config: ModelConfig) = Model(config = config) + } + + /** + * An interface that defines how to map each variant of [Model] to a value of type [T]. + */ + interface Visitor { + + fun visitString(string: String): T + + fun visitConfig(config: ModelConfig): T + + /** + * Maps an unknown variant of [Model] to a value of type [T]. + * + * An instance of [Model] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Model: $json") + } + } + + internal class Deserializer : BaseDeserializer(Model::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Model { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Model(config = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Model(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from array). + 0 -> Model(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Model::class) { + + override fun serialize( + value: Model, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.config != null -> generator.writeObject(value.config) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Model") + } + } + } + } + + class Provider @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPENAI = of("openai") + + @JvmField val ANTHROPIC = of("anthropic") + + @JvmField val GOOGLE = of("google") + + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) + } + + /** An enum containing [Provider]'s known values. */ + enum class Known { + OPENAI, + ANTHROPIC, + GOOGLE, + } + + /** + * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Provider] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPENAI, + ANTHROPIC, + GOOGLE, + /** + * An enum member indicating that [Provider] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPENAI -> Value.OPENAI + ANTHROPIC -> Value.ANTHROPIC + GOOGLE -> Value.GOOGLE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + OPENAI -> Known.OPENAI + ANTHROPIC -> Known.ANTHROPIC + GOOGLE -> Known.GOOGLE + else -> throw StagehandInvalidDataException("Unknown Provider: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Provider = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Provider && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AgentConfig && + cua == other.cua && + model == other.model && + provider == other.provider && + systemPrompt == other.systemPrompt && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(cua, model, provider, systemPrompt, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AgentConfig{cua=$cua, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" + } + + class ExecuteOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val instruction: JsonField, + private val highlightCursor: JsonField, + private val maxSteps: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("highlightCursor") + @ExcludeMissing + highlightCursor: JsonField = JsonMissing.of(), + @JsonProperty("maxSteps") @ExcludeMissing maxSteps: JsonField = JsonMissing.of(), + ) : this(instruction, highlightCursor, maxSteps, mutableMapOf()) + + /** + * Task for the agent to complete + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun instruction(): String = instruction.getRequired("instruction") + + /** + * Visually highlight the cursor during actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun highlightCursor(): Optional = highlightCursor.getOptional("highlightCursor") + + /** + * Maximum number of steps the agent can take + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [highlightCursor]. + * + * Unlike [highlightCursor], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("highlightCursor") + @ExcludeMissing + fun _highlightCursor(): JsonField = highlightCursor + + /** + * Returns the raw JSON value of [maxSteps]. + * + * Unlike [maxSteps], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("maxSteps") @ExcludeMissing fun _maxSteps(): JsonField = maxSteps + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ExecuteOptions]. + * + * The following fields are required: + * ```java + * .instruction() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ExecuteOptions]. */ + class Builder internal constructor() { + + private var instruction: JsonField? = null + private var highlightCursor: JsonField = JsonMissing.of() + private var maxSteps: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(executeOptions: ExecuteOptions) = apply { + instruction = executeOptions.instruction + highlightCursor = executeOptions.highlightCursor + maxSteps = executeOptions.maxSteps + additionalProperties = executeOptions.additionalProperties.toMutableMap() + } + + /** Task for the agent to complete */ + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + /** Visually highlight the cursor during actions */ + fun highlightCursor(highlightCursor: Boolean) = + highlightCursor(JsonField.of(highlightCursor)) + + /** + * Sets [Builder.highlightCursor] to an arbitrary JSON value. + * + * You should usually call [Builder.highlightCursor] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun highlightCursor(highlightCursor: JsonField) = apply { + this.highlightCursor = highlightCursor + } + + /** Maximum number of steps the agent can take */ + fun maxSteps(maxSteps: Long) = maxSteps(JsonField.of(maxSteps)) + + /** + * Sets [Builder.maxSteps] to an arbitrary JSON value. + * + * You should usually call [Builder.maxSteps] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxSteps(maxSteps: JsonField) = apply { this.maxSteps = maxSteps } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ExecuteOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .instruction() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExecuteOptions = + ExecuteOptions( + checkRequired("instruction", instruction), + highlightCursor, + maxSteps, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ExecuteOptions = apply { + if (validated) { + return@apply + } + + instruction() + highlightCursor() + maxSteps() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (instruction.asKnown().isPresent) 1 else 0) + + (if (highlightCursor.asKnown().isPresent) 1 else 0) + + (if (maxSteps.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExecuteOptions && + instruction == other.instruction && + highlightCursor == other.highlightCursor && + maxSteps == other.maxSteps && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(instruction, highlightCursor, maxSteps, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" + } + + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExecuteAgentParams && + sessionId == other.sessionId && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionExecuteAgentParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt new file mode 100644 index 0000000..6fdda9d --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt @@ -0,0 +1,212 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkKnown +import com.stagehand.api.core.toImmutable +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class SessionExecuteAgentResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val message: JsonField, + private val steps: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), + @JsonProperty("steps") @ExcludeMissing steps: JsonField> = JsonMissing.of(), + ) : this(message, steps, mutableMapOf()) + + /** + * Final message from the agent + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun message(): Optional = message.getOptional("message") + + /** + * Steps taken by the agent + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun steps(): Optional> = steps.getOptional("steps") + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [steps]. + * + * Unlike [steps], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("steps") @ExcludeMissing fun _steps(): JsonField> = steps + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionExecuteAgentResponse]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExecuteAgentResponse]. */ + class Builder internal constructor() { + + private var message: JsonField = JsonMissing.of() + private var steps: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionExecuteAgentResponse: SessionExecuteAgentResponse) = apply { + message = sessionExecuteAgentResponse.message + steps = sessionExecuteAgentResponse.steps.map { it.toMutableList() } + additionalProperties = sessionExecuteAgentResponse.additionalProperties.toMutableMap() + } + + /** Final message from the agent */ + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** Steps taken by the agent */ + fun steps(steps: List) = steps(JsonField.of(steps)) + + /** + * Sets [Builder.steps] to an arbitrary JSON value. + * + * You should usually call [Builder.steps] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun steps(steps: JsonField>) = apply { + this.steps = steps.map { it.toMutableList() } + } + + /** + * Adds a single [JsonValue] to [steps]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addStep(step: JsonValue) = apply { + steps = + (steps ?: JsonField.of(mutableListOf())).also { checkKnown("steps", it).add(step) } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionExecuteAgentResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionExecuteAgentResponse = + SessionExecuteAgentResponse( + message, + (steps ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SessionExecuteAgentResponse = apply { + if (validated) { + return@apply + } + + message() + steps() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (message.asKnown().isPresent) 1 else 0) + (steps.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExecuteAgentResponse && + message == other.message && + steps == other.steps && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(message, steps, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionExecuteAgentResponse{message=$message, steps=$steps, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt new file mode 100644 index 0000000..7d0c9a4 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt @@ -0,0 +1,1064 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.core.toImmutable +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Extracts data from the current page using natural language instructions and optional JSON schema + * for structured output. + */ +class SessionExtractParams +private constructor( + private val sessionId: String?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun sessionId(): Optional = Optional.ofNullable(sessionId) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** + * Frame ID to extract from + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * Natural language instruction for extraction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun instruction(): Optional = body.instruction() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * JSON Schema for structured output + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun schema(): Optional = body.schema() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _instruction(): JsonField = body._instruction() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + /** + * Returns the raw JSON value of [schema]. + * + * Unlike [schema], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _schema(): JsonField = body._schema() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionExtractParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionExtractParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExtractParams]. */ + class Builder internal constructor() { + + private var sessionId: String? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionExtractParams: SessionExtractParams) = apply { + sessionId = sessionExtractParams.sessionId + xStreamResponse = sessionExtractParams.xStreamResponse + body = sessionExtractParams.body.toBuilder() + additionalHeaders = sessionExtractParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionExtractParams.additionalQueryParams.toBuilder() + } + + fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } + + /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ + fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) + + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [frameId] + * - [instruction] + * - [options] + * - [schema] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Frame ID to extract from */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + /** Natural language instruction for extraction */ + fun instruction(instruction: String) = apply { body.instruction(instruction) } + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun instruction(instruction: JsonField) = apply { body.instruction(instruction) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + /** JSON Schema for structured output */ + fun schema(schema: Schema) = apply { body.schema(schema) } + + /** + * Sets [Builder.schema] to an arbitrary JSON value. + * + * You should usually call [Builder.schema] with a well-typed [Schema] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun schema(schema: JsonField) = apply { body.schema(schema) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionExtractParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionExtractParams = + SessionExtractParams( + sessionId, + xStreamResponse, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> sessionId ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val frameId: JsonField, + private val instruction: JsonField, + private val options: JsonField, + private val schema: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + @JsonProperty("schema") @ExcludeMissing schema: JsonField = JsonMissing.of(), + ) : this(frameId, instruction, options, schema, mutableMapOf()) + + /** + * Frame ID to extract from + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * Natural language instruction for extraction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun instruction(): Optional = instruction.getOptional("instruction") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * JSON Schema for structured output + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun schema(): Optional = schema.getOptional("schema") + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + /** + * Returns the raw JSON value of [schema]. + * + * Unlike [schema], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("schema") @ExcludeMissing fun _schema(): JsonField = schema + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var frameId: JsonField = JsonMissing.of() + private var instruction: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var schema: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + frameId = body.frameId + instruction = body.instruction + options = body.options + schema = body.schema + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Frame ID to extract from */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + /** Natural language instruction for extraction */ + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + /** JSON Schema for structured output */ + fun schema(schema: Schema) = schema(JsonField.of(schema)) + + /** + * Sets [Builder.schema] to an arbitrary JSON value. + * + * You should usually call [Builder.schema] with a well-typed [Schema] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun schema(schema: JsonField) = apply { this.schema = schema } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body(frameId, instruction, options, schema, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + frameId() + instruction() + options().ifPresent { it.validate() } + schema().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (frameId.asKnown().isPresent) 1 else 0) + + (if (instruction.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + (schema.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + frameId == other.frameId && + instruction == other.instruction && + options == other.options && + schema == other.schema && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(frameId, instruction, options, schema, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{frameId=$frameId, instruction=$instruction, options=$options, schema=$schema, additionalProperties=$additionalProperties}" + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val selector: JsonField, + private val timeout: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + ) : this(model, selector, timeout, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Extract only from elements matching this selector + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun selector(): Optional = selector.getOptional("selector") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var selector: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + model = options.model + selector = options.selector + timeout = options.timeout + additionalProperties = options.additionalProperties.toMutableMap() + } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Extract only from elements matching this selector */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + fun timeout(timeout: Long) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(model, selector, timeout, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + model().ifPresent { it.validate() } + selector() + timeout() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + model == other.model && + selector == other.selector && + timeout == other.timeout && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, selector, timeout, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" + } + + /** JSON Schema for structured output */ + class Schema + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Schema]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Schema]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(schema: Schema) = apply { + additionalProperties = schema.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Schema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Schema = Schema(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Schema = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Schema && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Schema{additionalProperties=$additionalProperties}" + } + + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExtractParams && + sessionId == other.sessionId && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionExtractParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt new file mode 100644 index 0000000..3126a4c --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt @@ -0,0 +1,459 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.BaseDeserializer +import com.stagehand.api.core.BaseSerializer +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.allMaxBy +import com.stagehand.api.core.getOrThrow +import com.stagehand.api.core.toImmutable +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional + +/** Default extraction result */ +@JsonDeserialize(using = SessionExtractResponse.Deserializer::class) +@JsonSerialize(using = SessionExtractResponse.Serializer::class) +class SessionExtractResponse +private constructor( + private val extraction: Extraction? = null, + private val unionMember1: UnionMember1? = null, + private val _json: JsonValue? = null, +) { + + /** Default extraction result */ + fun extraction(): Optional = Optional.ofNullable(extraction) + + /** Structured data matching provided schema */ + fun unionMember1(): Optional = Optional.ofNullable(unionMember1) + + fun isExtraction(): Boolean = extraction != null + + fun isUnionMember1(): Boolean = unionMember1 != null + + /** Default extraction result */ + fun asExtraction(): Extraction = extraction.getOrThrow("extraction") + + /** Structured data matching provided schema */ + fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + extraction != null -> visitor.visitExtraction(extraction) + unionMember1 != null -> visitor.visitUnionMember1(unionMember1) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): SessionExtractResponse = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitExtraction(extraction: Extraction) { + extraction.validate() + } + + override fun visitUnionMember1(unionMember1: UnionMember1) { + unionMember1.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitExtraction(extraction: Extraction) = extraction.validity() + + override fun visitUnionMember1(unionMember1: UnionMember1) = unionMember1.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExtractResponse && + extraction == other.extraction && + unionMember1 == other.unionMember1 + } + + override fun hashCode(): Int = Objects.hash(extraction, unionMember1) + + override fun toString(): String = + when { + extraction != null -> "SessionExtractResponse{extraction=$extraction}" + unionMember1 != null -> "SessionExtractResponse{unionMember1=$unionMember1}" + _json != null -> "SessionExtractResponse{_unknown=$_json}" + else -> throw IllegalStateException("Invalid SessionExtractResponse") + } + + companion object { + + /** Default extraction result */ + @JvmStatic + fun ofExtraction(extraction: Extraction) = SessionExtractResponse(extraction = extraction) + + /** Structured data matching provided schema */ + @JvmStatic + fun ofUnionMember1(unionMember1: UnionMember1) = + SessionExtractResponse(unionMember1 = unionMember1) + } + + /** + * An interface that defines how to map each variant of [SessionExtractResponse] to a value of + * type [T]. + */ + interface Visitor { + + /** Default extraction result */ + fun visitExtraction(extraction: Extraction): T + + /** Structured data matching provided schema */ + fun visitUnionMember1(unionMember1: UnionMember1): T + + /** + * Maps an unknown variant of [SessionExtractResponse] to a value of type [T]. + * + * An instance of [SessionExtractResponse] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK is + * on an older version than the API, then the API may respond with new variants that the SDK + * is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown SessionExtractResponse: $json") + } + } + + internal class Deserializer : + BaseDeserializer(SessionExtractResponse::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): SessionExtractResponse { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + SessionExtractResponse(extraction = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + SessionExtractResponse(unionMember1 = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with all + // the possible variants (e.g. deserializing from boolean). + 0 -> SessionExtractResponse(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(SessionExtractResponse::class) { + + override fun serialize( + value: SessionExtractResponse, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.extraction != null -> generator.writeObject(value.extraction) + value.unionMember1 != null -> generator.writeObject(value.unionMember1) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid SessionExtractResponse") + } + } + } + + /** Default extraction result */ + class Extraction + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val extraction: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("extraction") + @ExcludeMissing + extraction: JsonField = JsonMissing.of() + ) : this(extraction, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun extraction(): Optional = extraction.getOptional("extraction") + + /** + * Returns the raw JSON value of [extraction]. + * + * Unlike [extraction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("extraction") + @ExcludeMissing + fun _extraction(): JsonField = extraction + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Extraction]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Extraction]. */ + class Builder internal constructor() { + + private var extraction: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(extraction: Extraction) = apply { + this.extraction = extraction.extraction + additionalProperties = extraction.additionalProperties.toMutableMap() + } + + fun extraction(extraction: String) = extraction(JsonField.of(extraction)) + + /** + * Sets [Builder.extraction] to an arbitrary JSON value. + * + * You should usually call [Builder.extraction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun extraction(extraction: JsonField) = apply { this.extraction = extraction } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Extraction]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Extraction = Extraction(extraction, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Extraction = apply { + if (validated) { + return@apply + } + + extraction() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (if (extraction.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Extraction && + extraction == other.extraction && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(extraction, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Extraction{extraction=$extraction, additionalProperties=$additionalProperties}" + } + + /** Structured data matching provided schema */ + class UnionMember1 + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [UnionMember1]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UnionMember1]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(unionMember1: UnionMember1) = apply { + additionalProperties = unionMember1.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [UnionMember1]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): UnionMember1 = UnionMember1(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): UnionMember1 = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is UnionMember1 && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "UnionMember1{additionalProperties=$additionalProperties}" + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt new file mode 100644 index 0000000..634a032 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt @@ -0,0 +1,992 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Navigates the browser to the specified URL and waits for page load. */ +class SessionNavigateParams +private constructor( + private val sessionId: String?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun sessionId(): Optional = Optional.ofNullable(sessionId) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** + * URL to navigate to + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun url(): String = body.url() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _url(): JsonField = body._url() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionNavigateParams]. + * + * The following fields are required: + * ```java + * .url() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionNavigateParams]. */ + class Builder internal constructor() { + + private var sessionId: String? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionNavigateParams: SessionNavigateParams) = apply { + sessionId = sessionNavigateParams.sessionId + xStreamResponse = sessionNavigateParams.xStreamResponse + body = sessionNavigateParams.body.toBuilder() + additionalHeaders = sessionNavigateParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionNavigateParams.additionalQueryParams.toBuilder() + } + + fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } + + /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ + fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) + + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [url] + * - [frameId] + * - [options] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** URL to navigate to */ + fun url(url: String) = apply { body.url(url) } + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun url(url: JsonField) = apply { body.url(url) } + + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionNavigateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionNavigateParams = + SessionNavigateParams( + sessionId, + xStreamResponse, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> sessionId ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val url: JsonField, + private val frameId: JsonField, + private val options: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + ) : this(url, frameId, options, mutableMapOf()) + + /** + * URL to navigate to + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun url(): String = url.getRequired("url") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .url() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var url: JsonField? = null + private var frameId: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + url = body.url + frameId = body.frameId + options = body.options + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** URL to navigate to */ + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("url", url), + frameId, + options, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + url() + frameId() + options().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (url.asKnown().isPresent) 1 else 0) + + (if (frameId.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + url == other.url && + frameId == other.frameId && + options == other.options && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(url, frameId, options, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{url=$url, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val waitUntil: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("waitUntil") + @ExcludeMissing + waitUntil: JsonField = JsonMissing.of() + ) : this(waitUntil, mutableMapOf()) + + /** + * When to consider navigation complete + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun waitUntil(): Optional = waitUntil.getOptional("waitUntil") + + /** + * Returns the raw JSON value of [waitUntil]. + * + * Unlike [waitUntil], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("waitUntil") + @ExcludeMissing + fun _waitUntil(): JsonField = waitUntil + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var waitUntil: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + waitUntil = options.waitUntil + additionalProperties = options.additionalProperties.toMutableMap() + } + + /** When to consider navigation complete */ + fun waitUntil(waitUntil: WaitUntil) = waitUntil(JsonField.of(waitUntil)) + + /** + * Sets [Builder.waitUntil] to an arbitrary JSON value. + * + * You should usually call [Builder.waitUntil] with a well-typed [WaitUntil] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun waitUntil(waitUntil: JsonField) = apply { this.waitUntil = waitUntil } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = Options(waitUntil, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + waitUntil().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (waitUntil.asKnown().getOrNull()?.validity() ?: 0) + + /** When to consider navigation complete */ + class WaitUntil @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val LOAD = of("load") + + @JvmField val DOMCONTENTLOADED = of("domcontentloaded") + + @JvmField val NETWORKIDLE = of("networkidle") + + @JvmStatic fun of(value: String) = WaitUntil(JsonField.of(value)) + } + + /** An enum containing [WaitUntil]'s known values. */ + enum class Known { + LOAD, + DOMCONTENTLOADED, + NETWORKIDLE, + } + + /** + * An enum containing [WaitUntil]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [WaitUntil] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + LOAD, + DOMCONTENTLOADED, + NETWORKIDLE, + /** + * An enum member indicating that [WaitUntil] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + LOAD -> Value.LOAD + DOMCONTENTLOADED -> Value.DOMCONTENTLOADED + NETWORKIDLE -> Value.NETWORKIDLE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + LOAD -> Known.LOAD + DOMCONTENTLOADED -> Known.DOMCONTENTLOADED + NETWORKIDLE -> Known.NETWORKIDLE + else -> throw StagehandInvalidDataException("Unknown WaitUntil: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): WaitUntil = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is WaitUntil && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + waitUntil == other.waitUntil && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(waitUntil, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{waitUntil=$waitUntil, additionalProperties=$additionalProperties}" + } + + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionNavigateParams && + sessionId == other.sessionId && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionNavigateParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt new file mode 100644 index 0000000..b6a5d86 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt @@ -0,0 +1,216 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional + +/** Navigation response (may be null) */ +class SessionNavigateResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val ok: JsonField, + private val status: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("ok") @ExcludeMissing ok: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(ok, status, url, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun ok(): Optional = ok.getOptional("ok") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun status(): Optional = status.getOptional("status") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [ok]. + * + * Unlike [ok], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("ok") @ExcludeMissing fun _ok(): JsonField = ok + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionNavigateResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionNavigateResponse]. */ + class Builder internal constructor() { + + private var ok: JsonField = JsonMissing.of() + private var status: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionNavigateResponse: SessionNavigateResponse) = apply { + ok = sessionNavigateResponse.ok + status = sessionNavigateResponse.status + url = sessionNavigateResponse.url + additionalProperties = sessionNavigateResponse.additionalProperties.toMutableMap() + } + + fun ok(ok: Boolean) = ok(JsonField.of(ok)) + + /** + * Sets [Builder.ok] to an arbitrary JSON value. + * + * You should usually call [Builder.ok] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun ok(ok: JsonField) = apply { this.ok = ok } + + fun status(status: Long) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionNavigateResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionNavigateResponse = + SessionNavigateResponse(ok, status, url, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionNavigateResponse = apply { + if (validated) { + return@apply + } + + ok() + status() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (ok.asKnown().isPresent) 1 else 0) + + (if (status.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionNavigateResponse && + ok == other.ok && + status == other.status && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(ok, status, url, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionNavigateResponse{ok=$ok, status=$status, url=$url, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt new file mode 100644 index 0000000..e3d18de --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt @@ -0,0 +1,902 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Returns a list of candidate actions that can be performed on the page, optionally filtered by + * natural language instruction. + */ +class SessionObserveParams +private constructor( + private val sessionId: String?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun sessionId(): Optional = Optional.ofNullable(sessionId) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** + * Frame ID to observe + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * Natural language instruction to filter actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun instruction(): Optional = body.instruction() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _instruction(): JsonField = body._instruction() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionObserveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionObserveParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionObserveParams]. */ + class Builder internal constructor() { + + private var sessionId: String? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionObserveParams: SessionObserveParams) = apply { + sessionId = sessionObserveParams.sessionId + xStreamResponse = sessionObserveParams.xStreamResponse + body = sessionObserveParams.body.toBuilder() + additionalHeaders = sessionObserveParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionObserveParams.additionalQueryParams.toBuilder() + } + + fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } + + /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ + fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) + + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [frameId] + * - [instruction] + * - [options] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Frame ID to observe */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + /** Natural language instruction to filter actions */ + fun instruction(instruction: String) = apply { body.instruction(instruction) } + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun instruction(instruction: JsonField) = apply { body.instruction(instruction) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionObserveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionObserveParams = + SessionObserveParams( + sessionId, + xStreamResponse, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> sessionId ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val frameId: JsonField, + private val instruction: JsonField, + private val options: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + ) : this(frameId, instruction, options, mutableMapOf()) + + /** + * Frame ID to observe + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * Natural language instruction to filter actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun instruction(): Optional = instruction.getOptional("instruction") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var frameId: JsonField = JsonMissing.of() + private var instruction: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + frameId = body.frameId + instruction = body.instruction + options = body.options + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Frame ID to observe */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + /** Natural language instruction to filter actions */ + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body(frameId, instruction, options, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + frameId() + instruction() + options().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (frameId.asKnown().isPresent) 1 else 0) + + (if (instruction.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + frameId == other.frameId && + instruction == other.instruction && + options == other.options && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(frameId, instruction, options, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{frameId=$frameId, instruction=$instruction, options=$options, additionalProperties=$additionalProperties}" + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val selector: JsonField, + private val timeout: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + ) : this(model, selector, timeout, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Observe only elements matching this selector + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun selector(): Optional = selector.getOptional("selector") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var selector: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + model = options.model + selector = options.selector + timeout = options.timeout + additionalProperties = options.additionalProperties.toMutableMap() + } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Observe only elements matching this selector */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + fun timeout(timeout: Long) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(model, selector, timeout, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + model().ifPresent { it.validate() } + selector() + timeout() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + model == other.model && + selector == other.selector && + timeout == other.timeout && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, selector, timeout, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" + } + + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionObserveParams && + sessionId == other.sessionId && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionObserveParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt new file mode 100644 index 0000000..4b7050c --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt @@ -0,0 +1,1266 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.Enum +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.Params +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.http.QueryParams +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Initializes a new Stagehand session with a browser instance. Returns a session ID that must be + * used for all subsequent requests. + */ +class SessionStartParams +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * Environment to run the browser in + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun env(): Env = body.env() + + /** + * API key for Browserbase (required when env=BROWSERBASE) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun apiKey(): Optional = body.apiKey() + + /** + * Timeout in ms to wait for DOM to settle + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun domSettleTimeout(): Optional = body.domSettleTimeout() + + /** + * Options for local browser launch + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun localBrowserLaunchOptions(): Optional = + body.localBrowserLaunchOptions() + + /** + * AI model to use for actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun model(): Optional = body.model() + + /** + * Project ID for Browserbase (required when env=BROWSERBASE) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun projectId(): Optional = body.projectId() + + /** + * Enable self-healing for failed actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun selfHeal(): Optional = body.selfHeal() + + /** + * Custom system prompt for AI actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun systemPrompt(): Optional = body.systemPrompt() + + /** + * Logging verbosity level + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun verbose(): Optional = body.verbose() + + /** + * Returns the raw JSON value of [env]. + * + * Unlike [env], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _env(): JsonField = body._env() + + /** + * Returns the raw JSON value of [apiKey]. + * + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _apiKey(): JsonField = body._apiKey() + + /** + * Returns the raw JSON value of [domSettleTimeout]. + * + * Unlike [domSettleTimeout], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _domSettleTimeout(): JsonField = body._domSettleTimeout() + + /** + * Returns the raw JSON value of [localBrowserLaunchOptions]. + * + * Unlike [localBrowserLaunchOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + fun _localBrowserLaunchOptions(): JsonField = + body._localBrowserLaunchOptions() + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _model(): JsonField = body._model() + + /** + * Returns the raw JSON value of [projectId]. + * + * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _projectId(): JsonField = body._projectId() + + /** + * Returns the raw JSON value of [selfHeal]. + * + * Unlike [selfHeal], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _selfHeal(): JsonField = body._selfHeal() + + /** + * Returns the raw JSON value of [systemPrompt]. + * + * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _systemPrompt(): JsonField = body._systemPrompt() + + /** + * Returns the raw JSON value of [verbose]. + * + * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _verbose(): JsonField = body._verbose() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionStartParams]. + * + * The following fields are required: + * ```java + * .env() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionStartParams]. */ + class Builder internal constructor() { + + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionStartParams: SessionStartParams) = apply { + body = sessionStartParams.body.toBuilder() + additionalHeaders = sessionStartParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionStartParams.additionalQueryParams.toBuilder() + } + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [env] + * - [apiKey] + * - [domSettleTimeout] + * - [localBrowserLaunchOptions] + * - [model] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Environment to run the browser in */ + fun env(env: Env) = apply { body.env(env) } + + /** + * Sets [Builder.env] to an arbitrary JSON value. + * + * You should usually call [Builder.env] with a well-typed [Env] value instead. This method + * is primarily for setting the field to an undocumented or not yet supported value. + */ + fun env(env: JsonField) = apply { body.env(env) } + + /** API key for Browserbase (required when env=BROWSERBASE) */ + fun apiKey(apiKey: String) = apply { body.apiKey(apiKey) } + + /** + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun apiKey(apiKey: JsonField) = apply { body.apiKey(apiKey) } + + /** Timeout in ms to wait for DOM to settle */ + fun domSettleTimeout(domSettleTimeout: Long) = apply { + body.domSettleTimeout(domSettleTimeout) + } + + /** + * Sets [Builder.domSettleTimeout] to an arbitrary JSON value. + * + * You should usually call [Builder.domSettleTimeout] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun domSettleTimeout(domSettleTimeout: JsonField) = apply { + body.domSettleTimeout(domSettleTimeout) + } + + /** Options for local browser launch */ + fun localBrowserLaunchOptions(localBrowserLaunchOptions: LocalBrowserLaunchOptions) = + apply { + body.localBrowserLaunchOptions(localBrowserLaunchOptions) + } + + /** + * Sets [Builder.localBrowserLaunchOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.localBrowserLaunchOptions] with a well-typed + * [LocalBrowserLaunchOptions] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun localBrowserLaunchOptions( + localBrowserLaunchOptions: JsonField + ) = apply { body.localBrowserLaunchOptions(localBrowserLaunchOptions) } + + /** AI model to use for actions */ + fun model(model: String) = apply { body.model(model) } + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun model(model: JsonField) = apply { body.model(model) } + + /** Project ID for Browserbase (required when env=BROWSERBASE) */ + fun projectId(projectId: String) = apply { body.projectId(projectId) } + + /** + * Sets [Builder.projectId] to an arbitrary JSON value. + * + * You should usually call [Builder.projectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun projectId(projectId: JsonField) = apply { body.projectId(projectId) } + + /** Enable self-healing for failed actions */ + fun selfHeal(selfHeal: Boolean) = apply { body.selfHeal(selfHeal) } + + /** + * Sets [Builder.selfHeal] to an arbitrary JSON value. + * + * You should usually call [Builder.selfHeal] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun selfHeal(selfHeal: JsonField) = apply { body.selfHeal(selfHeal) } + + /** Custom system prompt for AI actions */ + fun systemPrompt(systemPrompt: String) = apply { body.systemPrompt(systemPrompt) } + + /** + * Sets [Builder.systemPrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.systemPrompt] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun systemPrompt(systemPrompt: JsonField) = apply { + body.systemPrompt(systemPrompt) + } + + /** Logging verbosity level */ + fun verbose(verbose: Long) = apply { body.verbose(verbose) } + + /** + * Sets [Builder.verbose] to an arbitrary JSON value. + * + * You should usually call [Builder.verbose] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionStartParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .env() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionStartParams = + SessionStartParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val env: JsonField, + private val apiKey: JsonField, + private val domSettleTimeout: JsonField, + private val localBrowserLaunchOptions: JsonField, + private val model: JsonField, + private val projectId: JsonField, + private val selfHeal: JsonField, + private val systemPrompt: JsonField, + private val verbose: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("env") @ExcludeMissing env: JsonField = JsonMissing.of(), + @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), + @JsonProperty("domSettleTimeout") + @ExcludeMissing + domSettleTimeout: JsonField = JsonMissing.of(), + @JsonProperty("localBrowserLaunchOptions") + @ExcludeMissing + localBrowserLaunchOptions: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("projectId") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("selfHeal") + @ExcludeMissing + selfHeal: JsonField = JsonMissing.of(), + @JsonProperty("systemPrompt") + @ExcludeMissing + systemPrompt: JsonField = JsonMissing.of(), + @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), + ) : this( + env, + apiKey, + domSettleTimeout, + localBrowserLaunchOptions, + model, + projectId, + selfHeal, + systemPrompt, + verbose, + mutableMapOf(), + ) + + /** + * Environment to run the browser in + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun env(): Env = env.getRequired("env") + + /** + * API key for Browserbase (required when env=BROWSERBASE) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun apiKey(): Optional = apiKey.getOptional("apiKey") + + /** + * Timeout in ms to wait for DOM to settle + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun domSettleTimeout(): Optional = domSettleTimeout.getOptional("domSettleTimeout") + + /** + * Options for local browser launch + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun localBrowserLaunchOptions(): Optional = + localBrowserLaunchOptions.getOptional("localBrowserLaunchOptions") + + /** + * AI model to use for actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Project ID for Browserbase (required when env=BROWSERBASE) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun projectId(): Optional = projectId.getOptional("projectId") + + /** + * Enable self-healing for failed actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun selfHeal(): Optional = selfHeal.getOptional("selfHeal") + + /** + * Custom system prompt for AI actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") + + /** + * Logging verbosity level + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun verbose(): Optional = verbose.getOptional("verbose") + + /** + * Returns the raw JSON value of [env]. + * + * Unlike [env], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("env") @ExcludeMissing fun _env(): JsonField = env + + /** + * Returns the raw JSON value of [apiKey]. + * + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + + /** + * Returns the raw JSON value of [domSettleTimeout]. + * + * Unlike [domSettleTimeout], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("domSettleTimeout") + @ExcludeMissing + fun _domSettleTimeout(): JsonField = domSettleTimeout + + /** + * Returns the raw JSON value of [localBrowserLaunchOptions]. + * + * Unlike [localBrowserLaunchOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("localBrowserLaunchOptions") + @ExcludeMissing + fun _localBrowserLaunchOptions(): JsonField = + localBrowserLaunchOptions + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [projectId]. + * + * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("projectId") @ExcludeMissing fun _projectId(): JsonField = projectId + + /** + * Returns the raw JSON value of [selfHeal]. + * + * Unlike [selfHeal], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selfHeal") @ExcludeMissing fun _selfHeal(): JsonField = selfHeal + + /** + * Returns the raw JSON value of [systemPrompt]. + * + * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("systemPrompt") + @ExcludeMissing + fun _systemPrompt(): JsonField = systemPrompt + + /** + * Returns the raw JSON value of [verbose]. + * + * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .env() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var env: JsonField? = null + private var apiKey: JsonField = JsonMissing.of() + private var domSettleTimeout: JsonField = JsonMissing.of() + private var localBrowserLaunchOptions: JsonField = + JsonMissing.of() + private var model: JsonField = JsonMissing.of() + private var projectId: JsonField = JsonMissing.of() + private var selfHeal: JsonField = JsonMissing.of() + private var systemPrompt: JsonField = JsonMissing.of() + private var verbose: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + env = body.env + apiKey = body.apiKey + domSettleTimeout = body.domSettleTimeout + localBrowserLaunchOptions = body.localBrowserLaunchOptions + model = body.model + projectId = body.projectId + selfHeal = body.selfHeal + systemPrompt = body.systemPrompt + verbose = body.verbose + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Environment to run the browser in */ + fun env(env: Env) = env(JsonField.of(env)) + + /** + * Sets [Builder.env] to an arbitrary JSON value. + * + * You should usually call [Builder.env] with a well-typed [Env] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun env(env: JsonField) = apply { this.env = env } + + /** API key for Browserbase (required when env=BROWSERBASE) */ + fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + + /** + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + + /** Timeout in ms to wait for DOM to settle */ + fun domSettleTimeout(domSettleTimeout: Long) = + domSettleTimeout(JsonField.of(domSettleTimeout)) + + /** + * Sets [Builder.domSettleTimeout] to an arbitrary JSON value. + * + * You should usually call [Builder.domSettleTimeout] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun domSettleTimeout(domSettleTimeout: JsonField) = apply { + this.domSettleTimeout = domSettleTimeout + } + + /** Options for local browser launch */ + fun localBrowserLaunchOptions(localBrowserLaunchOptions: LocalBrowserLaunchOptions) = + localBrowserLaunchOptions(JsonField.of(localBrowserLaunchOptions)) + + /** + * Sets [Builder.localBrowserLaunchOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.localBrowserLaunchOptions] with a well-typed + * [LocalBrowserLaunchOptions] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun localBrowserLaunchOptions( + localBrowserLaunchOptions: JsonField + ) = apply { this.localBrowserLaunchOptions = localBrowserLaunchOptions } + + /** AI model to use for actions */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Project ID for Browserbase (required when env=BROWSERBASE) */ + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) + + /** + * Sets [Builder.projectId] to an arbitrary JSON value. + * + * You should usually call [Builder.projectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun projectId(projectId: JsonField) = apply { this.projectId = projectId } + + /** Enable self-healing for failed actions */ + fun selfHeal(selfHeal: Boolean) = selfHeal(JsonField.of(selfHeal)) + + /** + * Sets [Builder.selfHeal] to an arbitrary JSON value. + * + * You should usually call [Builder.selfHeal] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selfHeal(selfHeal: JsonField) = apply { this.selfHeal = selfHeal } + + /** Custom system prompt for AI actions */ + fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) + + /** + * Sets [Builder.systemPrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.systemPrompt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun systemPrompt(systemPrompt: JsonField) = apply { + this.systemPrompt = systemPrompt + } + + /** Logging verbosity level */ + fun verbose(verbose: Long) = verbose(JsonField.of(verbose)) + + /** + * Sets [Builder.verbose] to an arbitrary JSON value. + * + * You should usually call [Builder.verbose] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .env() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("env", env), + apiKey, + domSettleTimeout, + localBrowserLaunchOptions, + model, + projectId, + selfHeal, + systemPrompt, + verbose, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + env().validate() + apiKey() + domSettleTimeout() + localBrowserLaunchOptions().ifPresent { it.validate() } + model() + projectId() + selfHeal() + systemPrompt() + verbose() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (env.asKnown().getOrNull()?.validity() ?: 0) + + (if (apiKey.asKnown().isPresent) 1 else 0) + + (if (domSettleTimeout.asKnown().isPresent) 1 else 0) + + (localBrowserLaunchOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (model.asKnown().isPresent) 1 else 0) + + (if (projectId.asKnown().isPresent) 1 else 0) + + (if (selfHeal.asKnown().isPresent) 1 else 0) + + (if (systemPrompt.asKnown().isPresent) 1 else 0) + + (if (verbose.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + env == other.env && + apiKey == other.apiKey && + domSettleTimeout == other.domSettleTimeout && + localBrowserLaunchOptions == other.localBrowserLaunchOptions && + model == other.model && + projectId == other.projectId && + selfHeal == other.selfHeal && + systemPrompt == other.systemPrompt && + verbose == other.verbose && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + env, + apiKey, + domSettleTimeout, + localBrowserLaunchOptions, + model, + projectId, + selfHeal, + systemPrompt, + verbose, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{env=$env, apiKey=$apiKey, domSettleTimeout=$domSettleTimeout, localBrowserLaunchOptions=$localBrowserLaunchOptions, model=$model, projectId=$projectId, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, additionalProperties=$additionalProperties}" + } + + /** Environment to run the browser in */ + class Env @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val LOCAL = of("LOCAL") + + @JvmField val BROWSERBASE = of("BROWSERBASE") + + @JvmStatic fun of(value: String) = Env(JsonField.of(value)) + } + + /** An enum containing [Env]'s known values. */ + enum class Known { + LOCAL, + BROWSERBASE, + } + + /** + * An enum containing [Env]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Env] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + LOCAL, + BROWSERBASE, + /** An enum member indicating that [Env] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + LOCAL -> Value.LOCAL + BROWSERBASE -> Value.BROWSERBASE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + LOCAL -> Known.LOCAL + BROWSERBASE -> Known.BROWSERBASE + else -> throw StagehandInvalidDataException("Unknown Env: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Env = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Env && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Options for local browser launch */ + class LocalBrowserLaunchOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val headless: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("headless") + @ExcludeMissing + headless: JsonField = JsonMissing.of() + ) : this(headless, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun headless(): Optional = headless.getOptional("headless") + + /** + * Returns the raw JSON value of [headless]. + * + * Unlike [headless], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("headless") @ExcludeMissing fun _headless(): JsonField = headless + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [LocalBrowserLaunchOptions]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LocalBrowserLaunchOptions]. */ + class Builder internal constructor() { + + private var headless: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(localBrowserLaunchOptions: LocalBrowserLaunchOptions) = apply { + headless = localBrowserLaunchOptions.headless + additionalProperties = localBrowserLaunchOptions.additionalProperties.toMutableMap() + } + + fun headless(headless: Boolean) = headless(JsonField.of(headless)) + + /** + * Sets [Builder.headless] to an arbitrary JSON value. + * + * You should usually call [Builder.headless] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun headless(headless: JsonField) = apply { this.headless = headless } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [LocalBrowserLaunchOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LocalBrowserLaunchOptions = + LocalBrowserLaunchOptions(headless, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): LocalBrowserLaunchOptions = apply { + if (validated) { + return@apply + } + + headless() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (if (headless.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LocalBrowserLaunchOptions && + headless == other.headless && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(headless, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LocalBrowserLaunchOptions{headless=$headless, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionStartParams && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionStartParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt new file mode 100644 index 0000000..b8bc8da --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt @@ -0,0 +1,213 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.stagehand.api.core.ExcludeMissing +import com.stagehand.api.core.JsonField +import com.stagehand.api.core.JsonMissing +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.checkRequired +import com.stagehand.api.errors.StagehandInvalidDataException +import java.util.Collections +import java.util.Objects + +class SessionStartResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val available: JsonField, + private val sessionId: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("available") @ExcludeMissing available: JsonField = JsonMissing.of(), + @JsonProperty("sessionId") @ExcludeMissing sessionId: JsonField = JsonMissing.of(), + ) : this(available, sessionId, mutableMapOf()) + + /** + * Whether the session is ready to use + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun available(): Boolean = available.getRequired("available") + + /** + * Unique identifier for the session + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun sessionId(): String = sessionId.getRequired("sessionId") + + /** + * Returns the raw JSON value of [available]. + * + * Unlike [available], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("available") @ExcludeMissing fun _available(): JsonField = available + + /** + * Returns the raw JSON value of [sessionId]. + * + * Unlike [sessionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sessionId") @ExcludeMissing fun _sessionId(): JsonField = sessionId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionStartResponse]. + * + * The following fields are required: + * ```java + * .available() + * .sessionId() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionStartResponse]. */ + class Builder internal constructor() { + + private var available: JsonField? = null + private var sessionId: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionStartResponse: SessionStartResponse) = apply { + available = sessionStartResponse.available + sessionId = sessionStartResponse.sessionId + additionalProperties = sessionStartResponse.additionalProperties.toMutableMap() + } + + /** Whether the session is ready to use */ + fun available(available: Boolean) = available(JsonField.of(available)) + + /** + * Sets [Builder.available] to an arbitrary JSON value. + * + * You should usually call [Builder.available] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun available(available: JsonField) = apply { this.available = available } + + /** Unique identifier for the session */ + fun sessionId(sessionId: String) = sessionId(JsonField.of(sessionId)) + + /** + * Sets [Builder.sessionId] to an arbitrary JSON value. + * + * You should usually call [Builder.sessionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun sessionId(sessionId: JsonField) = apply { this.sessionId = sessionId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionStartResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .available() + * .sessionId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionStartResponse = + SessionStartResponse( + checkRequired("available", available), + checkRequired("sessionId", sessionId), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SessionStartResponse = apply { + if (validated) { + return@apply + } + + available() + sessionId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (available.asKnown().isPresent) 1 else 0) + + (if (sessionId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionStartResponse && + available == other.available && + sessionId == other.sessionId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(available, sessionId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionStartResponse{available=$available, sessionId=$sessionId, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt new file mode 100644 index 0000000..12589d9 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt @@ -0,0 +1,479 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services.async + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.http.HttpResponseFor +import com.stagehand.api.models.sessions.Action +import com.stagehand.api.models.sessions.SessionActParams +import com.stagehand.api.models.sessions.SessionActResponse +import com.stagehand.api.models.sessions.SessionEndParams +import com.stagehand.api.models.sessions.SessionEndResponse +import com.stagehand.api.models.sessions.SessionExecuteAgentParams +import com.stagehand.api.models.sessions.SessionExecuteAgentResponse +import com.stagehand.api.models.sessions.SessionExtractParams +import com.stagehand.api.models.sessions.SessionExtractResponse +import com.stagehand.api.models.sessions.SessionNavigateParams +import com.stagehand.api.models.sessions.SessionNavigateResponse +import com.stagehand.api.models.sessions.SessionObserveParams +import com.stagehand.api.models.sessions.SessionStartParams +import com.stagehand.api.models.sessions.SessionStartResponse +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer + +interface SessionServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): SessionServiceAsync + + /** + * Performs a browser action based on natural language instruction or a specific action object + * returned by observe(). + */ + fun act(sessionId: String, params: SessionActParams): CompletableFuture = + act(sessionId, params, RequestOptions.none()) + + /** @see act */ + fun act( + sessionId: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + act(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see act */ + fun act(params: SessionActParams): CompletableFuture = + act(params, RequestOptions.none()) + + /** @see act */ + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** Closes the browser and cleans up all resources associated with the session. */ + fun end(sessionId: String): CompletableFuture = + end(sessionId, SessionEndParams.none()) + + /** @see end */ + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + end(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see end */ + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + ): CompletableFuture = end(sessionId, params, RequestOptions.none()) + + /** @see end */ + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see end */ + fun end(params: SessionEndParams): CompletableFuture = + end(params, RequestOptions.none()) + + /** @see end */ + fun end( + sessionId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + end(sessionId, SessionEndParams.none(), requestOptions) + + /** Runs an autonomous agent that can perform multiple actions to complete a complex task. */ + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + ): CompletableFuture = + executeAgent(sessionId, params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams + ): CompletableFuture = executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** + * Extracts data from the current page using natural language instructions and optional JSON + * schema for structured output. + */ + fun extract(sessionId: String): CompletableFuture = + extract(sessionId, SessionExtractParams.none()) + + /** @see extract */ + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see extract */ + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): CompletableFuture = extract(sessionId, params, RequestOptions.none()) + + /** @see extract */ + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see extract */ + fun extract(params: SessionExtractParams): CompletableFuture = + extract(params, RequestOptions.none()) + + /** @see extract */ + fun extract( + sessionId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + extract(sessionId, SessionExtractParams.none(), requestOptions) + + /** Navigates the browser to the specified URL and waits for page load. */ + fun navigate( + sessionId: String, + params: SessionNavigateParams, + ): CompletableFuture> = + navigate(sessionId, params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + sessionId: String, + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams + ): CompletableFuture> = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** + * Returns a list of candidate actions that can be performed on the page, optionally filtered by + * natural language instruction. + */ + fun observe(sessionId: String): CompletableFuture> = + observe(sessionId, SessionObserveParams.none()) + + /** @see observe */ + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see observe */ + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): CompletableFuture> = observe(sessionId, params, RequestOptions.none()) + + /** @see observe */ + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see observe */ + fun observe(params: SessionObserveParams): CompletableFuture> = + observe(params, RequestOptions.none()) + + /** @see observe */ + fun observe( + sessionId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + observe(sessionId, SessionObserveParams.none(), requestOptions) + + /** + * Initializes a new Stagehand session with a browser instance. Returns a session ID that must + * be used for all subsequent requests. + */ + fun start(params: SessionStartParams): CompletableFuture = + start(params, RequestOptions.none()) + + /** @see start */ + fun start( + params: SessionStartParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** + * A view of [SessionServiceAsync] that provides access to raw HTTP responses for each method. + */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions( + modifier: Consumer + ): SessionServiceAsync.WithRawResponse + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/act`, but is otherwise the + * same as [SessionServiceAsync.act]. + */ + fun act( + sessionId: String, + params: SessionActParams, + ): CompletableFuture> = + act(sessionId, params, RequestOptions.none()) + + /** @see act */ + fun act( + sessionId: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + act(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see act */ + fun act(params: SessionActParams): CompletableFuture> = + act(params, RequestOptions.none()) + + /** @see act */ + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/end`, but is otherwise the + * same as [SessionServiceAsync.end]. + */ + fun end(sessionId: String): CompletableFuture> = + end(sessionId, SessionEndParams.none()) + + /** @see end */ + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + end(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see end */ + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + ): CompletableFuture> = + end(sessionId, params, RequestOptions.none()) + + /** @see end */ + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see end */ + fun end(params: SessionEndParams): CompletableFuture> = + end(params, RequestOptions.none()) + + /** @see end */ + fun end( + sessionId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + end(sessionId, SessionEndParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/agentExecute`, but is + * otherwise the same as [SessionServiceAsync.executeAgent]. + */ + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + ): CompletableFuture> = + executeAgent(sessionId, params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams + ): CompletableFuture> = + executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/extract`, but is otherwise + * the same as [SessionServiceAsync.extract]. + */ + fun extract(sessionId: String): CompletableFuture> = + extract(sessionId, SessionExtractParams.none()) + + /** @see extract */ + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see extract */ + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): CompletableFuture> = + extract(sessionId, params, RequestOptions.none()) + + /** @see extract */ + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see extract */ + fun extract( + params: SessionExtractParams + ): CompletableFuture> = + extract(params, RequestOptions.none()) + + /** @see extract */ + fun extract( + sessionId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + extract(sessionId, SessionExtractParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/navigate`, but is otherwise + * the same as [SessionServiceAsync.navigate]. + */ + fun navigate( + sessionId: String, + params: SessionNavigateParams, + ): CompletableFuture>> = + navigate(sessionId, params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + sessionId: String, + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams + ): CompletableFuture>> = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/observe`, but is otherwise + * the same as [SessionServiceAsync.observe]. + */ + fun observe(sessionId: String): CompletableFuture>> = + observe(sessionId, SessionObserveParams.none()) + + /** @see observe */ + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see observe */ + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): CompletableFuture>> = + observe(sessionId, params, RequestOptions.none()) + + /** @see observe */ + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> + + /** @see observe */ + fun observe( + params: SessionObserveParams + ): CompletableFuture>> = observe(params, RequestOptions.none()) + + /** @see observe */ + fun observe( + sessionId: String, + requestOptions: RequestOptions, + ): CompletableFuture>> = + observe(sessionId, SessionObserveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as + * [SessionServiceAsync.start]. + */ + fun start( + params: SessionStartParams + ): CompletableFuture> = + start(params, RequestOptions.none()) + + /** @see start */ + fun start( + params: SessionStartParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt new file mode 100644 index 0000000..a103a22 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt @@ -0,0 +1,347 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services.async + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.handlers.errorBodyHandler +import com.stagehand.api.core.handlers.errorHandler +import com.stagehand.api.core.handlers.jsonHandler +import com.stagehand.api.core.http.HttpMethod +import com.stagehand.api.core.http.HttpRequest +import com.stagehand.api.core.http.HttpResponse +import com.stagehand.api.core.http.HttpResponse.Handler +import com.stagehand.api.core.http.HttpResponseFor +import com.stagehand.api.core.http.json +import com.stagehand.api.core.http.parseable +import com.stagehand.api.core.prepareAsync +import com.stagehand.api.models.sessions.Action +import com.stagehand.api.models.sessions.SessionActParams +import com.stagehand.api.models.sessions.SessionActResponse +import com.stagehand.api.models.sessions.SessionEndParams +import com.stagehand.api.models.sessions.SessionEndResponse +import com.stagehand.api.models.sessions.SessionExecuteAgentParams +import com.stagehand.api.models.sessions.SessionExecuteAgentResponse +import com.stagehand.api.models.sessions.SessionExtractParams +import com.stagehand.api.models.sessions.SessionExtractResponse +import com.stagehand.api.models.sessions.SessionNavigateParams +import com.stagehand.api.models.sessions.SessionNavigateResponse +import com.stagehand.api.models.sessions.SessionObserveParams +import com.stagehand.api.models.sessions.SessionStartParams +import com.stagehand.api.models.sessions.SessionStartResponse +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.function.Consumer +import kotlin.jvm.optionals.getOrNull + +class SessionServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + SessionServiceAsync { + + private val withRawResponse: SessionServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): SessionServiceAsync.WithRawResponse = withRawResponse + + override fun withOptions(modifier: Consumer): SessionServiceAsync = + SessionServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + + override fun act( + params: SessionActParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{sessionId}/act + withRawResponse().act(params, requestOptions).thenApply { it.parse() } + + override fun end( + params: SessionEndParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{sessionId}/end + withRawResponse().end(params, requestOptions).thenApply { it.parse() } + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{sessionId}/agentExecute + withRawResponse().executeAgent(params, requestOptions).thenApply { it.parse() } + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{sessionId}/extract + withRawResponse().extract(params, requestOptions).thenApply { it.parse() } + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): CompletableFuture> = + // post /sessions/{sessionId}/navigate + withRawResponse().navigate(params, requestOptions).thenApply { it.parse() } + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): CompletableFuture> = + // post /sessions/{sessionId}/observe + withRawResponse().observe(params, requestOptions).thenApply { it.parse() } + + override fun start( + params: SessionStartParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/start + withRawResponse().start(params, requestOptions).thenApply { it.parse() } + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + SessionServiceAsync.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: Consumer + ): SessionServiceAsync.WithRawResponse = + SessionServiceAsyncImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + private val actHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun act( + params: SessionActParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "act") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { actHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val endHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun end( + params: SessionEndParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "end") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { endHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val executeAgentHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "agentExecute") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { executeAgentHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val extractHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "extract") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { extractHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val navigateHandler: Handler> = + jsonHandler>(clientOptions.jsonMapper) + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "navigate") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { navigateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.ifPresent { it.validate() } + } + } + } + } + } + + private val observeHandler: Handler> = + jsonHandler>(clientOptions.jsonMapper) + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "observe") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { observeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.forEach { it.validate() } + } + } + } + } + } + + private val startHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun start( + params: SessionStartParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", "start") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { startHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt new file mode 100644 index 0000000..b605953 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt @@ -0,0 +1,475 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services.blocking + +import com.google.errorprone.annotations.MustBeClosed +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.http.HttpResponseFor +import com.stagehand.api.models.sessions.Action +import com.stagehand.api.models.sessions.SessionActParams +import com.stagehand.api.models.sessions.SessionActResponse +import com.stagehand.api.models.sessions.SessionEndParams +import com.stagehand.api.models.sessions.SessionEndResponse +import com.stagehand.api.models.sessions.SessionExecuteAgentParams +import com.stagehand.api.models.sessions.SessionExecuteAgentResponse +import com.stagehand.api.models.sessions.SessionExtractParams +import com.stagehand.api.models.sessions.SessionExtractResponse +import com.stagehand.api.models.sessions.SessionNavigateParams +import com.stagehand.api.models.sessions.SessionNavigateResponse +import com.stagehand.api.models.sessions.SessionObserveParams +import com.stagehand.api.models.sessions.SessionStartParams +import com.stagehand.api.models.sessions.SessionStartResponse +import java.util.Optional +import java.util.function.Consumer + +interface SessionService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): SessionService + + /** + * Performs a browser action based on natural language instruction or a specific action object + * returned by observe(). + */ + fun act(sessionId: String, params: SessionActParams): SessionActResponse = + act(sessionId, params, RequestOptions.none()) + + /** @see act */ + fun act( + sessionId: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionActResponse = act(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see act */ + fun act(params: SessionActParams): SessionActResponse = act(params, RequestOptions.none()) + + /** @see act */ + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionActResponse + + /** Closes the browser and cleans up all resources associated with the session. */ + fun end(sessionId: String): SessionEndResponse = end(sessionId, SessionEndParams.none()) + + /** @see end */ + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionEndResponse = end(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see end */ + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + ): SessionEndResponse = end(sessionId, params, RequestOptions.none()) + + /** @see end */ + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionEndResponse + + /** @see end */ + fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) + + /** @see end */ + fun end(sessionId: String, requestOptions: RequestOptions): SessionEndResponse = + end(sessionId, SessionEndParams.none(), requestOptions) + + /** Runs an autonomous agent that can perform multiple actions to complete a complex task. */ + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + ): SessionExecuteAgentResponse = executeAgent(sessionId, params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExecuteAgentResponse = + executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see executeAgent */ + fun executeAgent(params: SessionExecuteAgentParams): SessionExecuteAgentResponse = + executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExecuteAgentResponse + + /** + * Extracts data from the current page using natural language instructions and optional JSON + * schema for structured output. + */ + fun extract(sessionId: String): SessionExtractResponse = + extract(sessionId, SessionExtractParams.none()) + + /** @see extract */ + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExtractResponse = + extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see extract */ + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): SessionExtractResponse = extract(sessionId, params, RequestOptions.none()) + + /** @see extract */ + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExtractResponse + + /** @see extract */ + fun extract(params: SessionExtractParams): SessionExtractResponse = + extract(params, RequestOptions.none()) + + /** @see extract */ + fun extract(sessionId: String, requestOptions: RequestOptions): SessionExtractResponse = + extract(sessionId, SessionExtractParams.none(), requestOptions) + + /** Navigates the browser to the specified URL and waits for page load. */ + fun navigate( + sessionId: String, + params: SessionNavigateParams, + ): Optional = navigate(sessionId, params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + sessionId: String, + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Optional = + navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see navigate */ + fun navigate(params: SessionNavigateParams): Optional = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Optional + + /** + * Returns a list of candidate actions that can be performed on the page, optionally filtered by + * natural language instruction. + */ + fun observe(sessionId: String): List = observe(sessionId, SessionObserveParams.none()) + + /** @see observe */ + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): List = observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see observe */ + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): List = observe(sessionId, params, RequestOptions.none()) + + /** @see observe */ + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): List + + /** @see observe */ + fun observe(params: SessionObserveParams): List = observe(params, RequestOptions.none()) + + /** @see observe */ + fun observe(sessionId: String, requestOptions: RequestOptions): List = + observe(sessionId, SessionObserveParams.none(), requestOptions) + + /** + * Initializes a new Stagehand session with a browser instance. Returns a session ID that must + * be used for all subsequent requests. + */ + fun start(params: SessionStartParams): SessionStartResponse = + start(params, RequestOptions.none()) + + /** @see start */ + fun start( + params: SessionStartParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionStartResponse + + /** A view of [SessionService] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse { + + /** + * Returns a view of this service with the given option modifications applied. + * + * The original service is not modified. + */ + fun withOptions(modifier: Consumer): SessionService.WithRawResponse + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/act`, but is otherwise the + * same as [SessionService.act]. + */ + @MustBeClosed + fun act(sessionId: String, params: SessionActParams): HttpResponseFor = + act(sessionId, params, RequestOptions.none()) + + /** @see act */ + @MustBeClosed + fun act( + sessionId: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + act(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see act */ + @MustBeClosed + fun act(params: SessionActParams): HttpResponseFor = + act(params, RequestOptions.none()) + + /** @see act */ + @MustBeClosed + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/end`, but is otherwise the + * same as [SessionService.end]. + */ + @MustBeClosed + fun end(sessionId: String): HttpResponseFor = + end(sessionId, SessionEndParams.none()) + + /** @see end */ + @MustBeClosed + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + end(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see end */ + @MustBeClosed + fun end( + sessionId: String, + params: SessionEndParams = SessionEndParams.none(), + ): HttpResponseFor = end(sessionId, params, RequestOptions.none()) + + /** @see end */ + @MustBeClosed + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see end */ + @MustBeClosed + fun end(params: SessionEndParams): HttpResponseFor = + end(params, RequestOptions.none()) + + /** @see end */ + @MustBeClosed + fun end( + sessionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + end(sessionId, SessionEndParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/agentExecute`, but is + * otherwise the same as [SessionService.executeAgent]. + */ + @MustBeClosed + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + ): HttpResponseFor = + executeAgent(sessionId, params, RequestOptions.none()) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + sessionId: String, + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + params: SessionExecuteAgentParams + ): HttpResponseFor = + executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/extract`, but is otherwise + * the same as [SessionService.extract]. + */ + @MustBeClosed + fun extract(sessionId: String): HttpResponseFor = + extract(sessionId, SessionExtractParams.none()) + + /** @see extract */ + @MustBeClosed + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see extract */ + @MustBeClosed + fun extract( + sessionId: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): HttpResponseFor = + extract(sessionId, params, RequestOptions.none()) + + /** @see extract */ + @MustBeClosed + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see extract */ + @MustBeClosed + fun extract(params: SessionExtractParams): HttpResponseFor = + extract(params, RequestOptions.none()) + + /** @see extract */ + @MustBeClosed + fun extract( + sessionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + extract(sessionId, SessionExtractParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/navigate`, but is otherwise + * the same as [SessionService.navigate]. + */ + @MustBeClosed + fun navigate( + sessionId: String, + params: SessionNavigateParams, + ): HttpResponseFor> = + navigate(sessionId, params, RequestOptions.none()) + + /** @see navigate */ + @MustBeClosed + fun navigate( + sessionId: String, + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see navigate */ + @MustBeClosed + fun navigate( + params: SessionNavigateParams + ): HttpResponseFor> = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + @MustBeClosed + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> + + /** + * Returns a raw HTTP response for `post /sessions/{sessionId}/observe`, but is otherwise + * the same as [SessionService.observe]. + */ + @MustBeClosed + fun observe(sessionId: String): HttpResponseFor> = + observe(sessionId, SessionObserveParams.none()) + + /** @see observe */ + @MustBeClosed + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) + + /** @see observe */ + @MustBeClosed + fun observe( + sessionId: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): HttpResponseFor> = observe(sessionId, params, RequestOptions.none()) + + /** @see observe */ + @MustBeClosed + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> + + /** @see observe */ + @MustBeClosed + fun observe(params: SessionObserveParams): HttpResponseFor> = + observe(params, RequestOptions.none()) + + /** @see observe */ + @MustBeClosed + fun observe( + sessionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor> = + observe(sessionId, SessionObserveParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as + * [SessionService.start]. + */ + @MustBeClosed + fun start(params: SessionStartParams): HttpResponseFor = + start(params, RequestOptions.none()) + + /** @see start */ + @MustBeClosed + fun start( + params: SessionStartParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt new file mode 100644 index 0000000..f154a4a --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt @@ -0,0 +1,319 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services.blocking + +import com.stagehand.api.core.ClientOptions +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.checkRequired +import com.stagehand.api.core.handlers.errorBodyHandler +import com.stagehand.api.core.handlers.errorHandler +import com.stagehand.api.core.handlers.jsonHandler +import com.stagehand.api.core.http.HttpMethod +import com.stagehand.api.core.http.HttpRequest +import com.stagehand.api.core.http.HttpResponse +import com.stagehand.api.core.http.HttpResponse.Handler +import com.stagehand.api.core.http.HttpResponseFor +import com.stagehand.api.core.http.json +import com.stagehand.api.core.http.parseable +import com.stagehand.api.core.prepare +import com.stagehand.api.models.sessions.Action +import com.stagehand.api.models.sessions.SessionActParams +import com.stagehand.api.models.sessions.SessionActResponse +import com.stagehand.api.models.sessions.SessionEndParams +import com.stagehand.api.models.sessions.SessionEndResponse +import com.stagehand.api.models.sessions.SessionExecuteAgentParams +import com.stagehand.api.models.sessions.SessionExecuteAgentResponse +import com.stagehand.api.models.sessions.SessionExtractParams +import com.stagehand.api.models.sessions.SessionExtractResponse +import com.stagehand.api.models.sessions.SessionNavigateParams +import com.stagehand.api.models.sessions.SessionNavigateResponse +import com.stagehand.api.models.sessions.SessionObserveParams +import com.stagehand.api.models.sessions.SessionStartParams +import com.stagehand.api.models.sessions.SessionStartResponse +import java.util.Optional +import java.util.function.Consumer +import kotlin.jvm.optionals.getOrNull + +class SessionServiceImpl internal constructor(private val clientOptions: ClientOptions) : + SessionService { + + private val withRawResponse: SessionService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): SessionService.WithRawResponse = withRawResponse + + override fun withOptions(modifier: Consumer): SessionService = + SessionServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + + override fun act(params: SessionActParams, requestOptions: RequestOptions): SessionActResponse = + // post /sessions/{sessionId}/act + withRawResponse().act(params, requestOptions).parse() + + override fun end(params: SessionEndParams, requestOptions: RequestOptions): SessionEndResponse = + // post /sessions/{sessionId}/end + withRawResponse().end(params, requestOptions).parse() + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): SessionExecuteAgentResponse = + // post /sessions/{sessionId}/agentExecute + withRawResponse().executeAgent(params, requestOptions).parse() + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): SessionExtractResponse = + // post /sessions/{sessionId}/extract + withRawResponse().extract(params, requestOptions).parse() + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): Optional = + // post /sessions/{sessionId}/navigate + withRawResponse().navigate(params, requestOptions).parse() + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): List = + // post /sessions/{sessionId}/observe + withRawResponse().observe(params, requestOptions).parse() + + override fun start( + params: SessionStartParams, + requestOptions: RequestOptions, + ): SessionStartResponse = + // post /sessions/start + withRawResponse().start(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + SessionService.WithRawResponse { + + private val errorHandler: Handler = + errorHandler(errorBodyHandler(clientOptions.jsonMapper)) + + override fun withOptions( + modifier: Consumer + ): SessionService.WithRawResponse = + SessionServiceImpl.WithRawResponseImpl( + clientOptions.toBuilder().apply(modifier::accept).build() + ) + + private val actHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun act( + params: SessionActParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "act") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { actHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val endHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun end( + params: SessionEndParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "end") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { endHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val executeAgentHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "agentExecute") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { executeAgentHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val extractHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "extract") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { extractHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val navigateHandler: Handler> = + jsonHandler>(clientOptions.jsonMapper) + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "navigate") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { navigateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.ifPresent { it.validate() } + } + } + } + } + + private val observeHandler: Handler> = + jsonHandler>(clientOptions.jsonMapper) + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("sessionId", params.sessionId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "observe") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { observeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.forEach { it.validate() } + } + } + } + } + + private val startHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun start( + params: SessionStartParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", "start") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { startHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro b/stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro new file mode 100644 index 0000000..246b6fe --- /dev/null +++ b/stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro @@ -0,0 +1,32 @@ +# Jackson uses reflection and depends heavily on runtime attributes. +-keepattributes Exceptions,InnerClasses,Signature,Deprecated,*Annotation* + +# Jackson uses Kotlin reflection utilities, which themselves use reflection to access things. +-keep class kotlin.reflect.** { *; } +-keep class kotlin.Metadata { *; } + +# Jackson uses reflection to access enum members (e.g. via `java.lang.Class.getEnumConstants()`). +-keepclassmembers class com.fasterxml.jackson.** extends java.lang.Enum { + ; + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +# Jackson uses reflection to access annotation members. +-keepclassmembers @interface com.fasterxml.jackson.annotation.** { + *; +} + +# Jackson uses reified type information to serialize and deserialize our classes (via `TypeReference`). +-keep class com.fasterxml.jackson.core.type.TypeReference { *; } +-keep class * extends com.fasterxml.jackson.core.type.TypeReference { *; } + +# Jackson uses reflection to access our class serializers and deserializers. +-keep @com.fasterxml.jackson.databind.annotation.JsonSerialize class com.stagehand.api.** { *; } +-keep @com.fasterxml.jackson.databind.annotation.JsonDeserialize class com.stagehand.api.** { *; } + +# Jackson uses reflection to serialize and deserialize our classes based on their constructors and annotated members. +-keepclassmembers class com.stagehand.api.** { + (...); + @com.fasterxml.jackson.annotation.* *; +} \ No newline at end of file diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt new file mode 100644 index 0000000..47f81ce --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt @@ -0,0 +1,62 @@ +package com.stagehand.api + +import java.lang.RuntimeException +import java.net.URL +import org.junit.jupiter.api.extension.BeforeAllCallback +import org.junit.jupiter.api.extension.ConditionEvaluationResult +import org.junit.jupiter.api.extension.ExecutionCondition +import org.junit.jupiter.api.extension.ExtensionContext + +class TestServerExtension : BeforeAllCallback, ExecutionCondition { + + override fun beforeAll(context: ExtensionContext?) { + try { + URL(BASE_URL).openConnection().connect() + } catch (e: Exception) { + throw RuntimeException( + """ + The test suite will not run without a mock Prism server running against your OpenAPI spec. + + You can set the environment variable `SKIP_MOCK_TESTS` to `true` to skip running any tests + that require the mock server. + + To fix: + + 1. Install Prism (requires Node 16+): + + With npm: + $ npm install -g @stoplight/prism-cli + + With yarn: + $ yarn global add @stoplight/prism-cli + + 2. Run the mock server + + To run the server, pass in the path of your OpenAPI spec to the prism command: + $ prism mock path/to/your.openapi.yml + """ + .trimIndent(), + e, + ) + } + } + + override fun evaluateExecutionCondition(context: ExtensionContext): ConditionEvaluationResult { + return if (System.getenv(SKIP_TESTS_ENV).toBoolean()) { + ConditionEvaluationResult.disabled( + "Environment variable $SKIP_TESTS_ENV is set to true" + ) + } else { + ConditionEvaluationResult.enabled( + "Environment variable $SKIP_TESTS_ENV is not set to true" + ) + } + } + + companion object { + + val BASE_URL = System.getenv("TEST_API_BASE_URL") ?: "http://localhost:4010" + + const val SKIP_TESTS_ENV: String = "SKIP_MOCK_TESTS" + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt new file mode 100644 index 0000000..153fd8f --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.core + +import com.stagehand.api.core.http.HttpClient +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +@ExtendWith(MockitoExtension::class) +internal class ClientOptionsTest { + + private val httpClient = mock() + + @Test + fun toBuilder_whenOriginalClientOptionsGarbageCollected_doesNotCloseOriginalClient() { + var clientOptions = + ClientOptions.builder().httpClient(httpClient).apiKey("My API Key").build() + verify(httpClient, never()).close() + + // Overwrite the `clientOptions` variable so that the original `ClientOptions` is GC'd. + clientOptions = clientOptions.toBuilder().build() + System.gc() + Thread.sleep(100) + + verify(httpClient, never()).close() + // This exists so that `clientOptions` is still reachable. + assertThat(clientOptions).isEqualTo(clientOptions) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt new file mode 100644 index 0000000..d4a23d2 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt @@ -0,0 +1,102 @@ +package com.stagehand.api.core + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.exc.MismatchedInputException +import com.fasterxml.jackson.module.kotlin.readValue +import java.time.LocalDateTime +import kotlin.reflect.KClass +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.catchThrowable +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource +import org.junitpioneer.jupiter.cartesian.CartesianTest + +internal class ObjectMappersTest { + + internal class ClassWithBooleanFieldPrefixedWithIs(private val isActive: JsonField) { + + @JsonProperty("is_active") @ExcludeMissing fun _isActive() = isActive + } + + @Test + fun write_whenFieldPrefixedWithIs_keepsPrefix() { + val value = ClassWithBooleanFieldPrefixedWithIs(JsonField.of(true)) + + val json = jsonMapper().writeValueAsString(value) + + assertThat(json).isEqualTo("{\"is_active\":true}") + } + + internal class Class(@get:JsonProperty("field") @JsonProperty("field") val field: String) + + enum class ShapeTestCase(val value: Any, val kClass: KClass<*>) { + STRING("Hello World!", String::class), + BOOLEAN(true, Boolean::class), + FLOAT(3.14F, Float::class), + DOUBLE(3.14, Double::class), + INTEGER(42, Int::class), + LONG(42L, Long::class), + MAP(mapOf("property" to "value"), Map::class), + CLASS(Class("Hello World!"), Class::class), + LIST(listOf(1, 2, 3), List::class); + + companion object { + val VALID_CONVERSIONS = + listOf( + FLOAT to DOUBLE, + FLOAT to INTEGER, + FLOAT to LONG, + DOUBLE to FLOAT, + DOUBLE to INTEGER, + DOUBLE to LONG, + INTEGER to FLOAT, + INTEGER to DOUBLE, + INTEGER to LONG, + LONG to FLOAT, + LONG to DOUBLE, + LONG to INTEGER, + CLASS to MAP, + // These aren't actually valid, but coercion configs don't work for String until + // v2.14.0: https://github.com/FasterXML/jackson-databind/issues/3240 + // We currently test on v2.13.4. + BOOLEAN to STRING, + FLOAT to STRING, + DOUBLE to STRING, + INTEGER to STRING, + LONG to STRING, + ) + } + } + + @CartesianTest + fun read(@CartesianTest.Enum shape1: ShapeTestCase, @CartesianTest.Enum shape2: ShapeTestCase) { + val jsonMapper = jsonMapper() + val json = jsonMapper.writeValueAsString(shape1.value) + + val e = catchThrowable { jsonMapper.readValue(json, shape2.kClass.java) } + + if (shape1 == shape2 || shape1 to shape2 in ShapeTestCase.VALID_CONVERSIONS) { + assertThat(e).isNull() + } else { + assertThat(e).isInstanceOf(MismatchedInputException::class.java) + } + } + + enum class LenientLocalDateTimeTestCase(val string: String) { + DATE("1998-04-21"), + DATE_TIME("1998-04-21T04:00:00"), + ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), + ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"), + } + + @ParameterizedTest + @EnumSource + fun readLocalDateTime_lenient(testCase: LenientLocalDateTimeTestCase) { + val jsonMapper = jsonMapper() + val json = jsonMapper.writeValueAsString(testCase.string) + + assertDoesNotThrow { jsonMapper().readValue(json) } + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt new file mode 100644 index 0000000..f5cf23d --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt @@ -0,0 +1,27 @@ +package com.stagehand.api.core + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PhantomReachableTest { + + @Test + fun closeWhenPhantomReachable_whenObservedIsGarbageCollected_closesCloseable() { + var closed = false + val closeable = AutoCloseable { closed = true } + + closeWhenPhantomReachable( + // Pass an inline object for the object to observe so that it becomes immediately + // unreachable. + Any(), + closeable, + ) + + assertThat(closed).isFalse() + + System.gc() + Thread.sleep(100) + + assertThat(closed).isTrue() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt new file mode 100644 index 0000000..b452f98 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt @@ -0,0 +1,33 @@ +package com.stagehand.api.core + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class UtilsTest { + @Test + fun contentDeepEquals() { + assertThat(42 contentEquals 42).isTrue() + assertThat(42 contentEquals "Hello World!").isFalse() + assertThat(byteArrayOf(1, 2, 3) contentEquals byteArrayOf(1, 2, 3)).isTrue() + assertThat(byteArrayOf(1, 2, 3) contentEquals byteArrayOf(1, 2, 4)).isFalse() + assertThat( + arrayOf(byteArrayOf(1, 2), byteArrayOf(3)) contentEquals + arrayOf(byteArrayOf(1, 2), byteArrayOf(3)) + ) + .isTrue() + assertThat( + arrayOf(byteArrayOf(1, 2), byteArrayOf(3)) contentEquals + arrayOf(byteArrayOf(1), byteArrayOf(2, 3)) + ) + .isFalse() + } + + @Test + fun contentToString() { + assertThat((42).contentToString()).isEqualTo("42") + assertThat("Hello World!".contentToString()).isEqualTo("Hello World!") + assertThat(byteArrayOf(1, 2, 3).contentToString()).isEqualTo("[1, 2, 3]") + assertThat(arrayOf(byteArrayOf(1, 2), byteArrayOf(3)).contentToString()) + .isEqualTo("[[1, 2], [3]]") + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt new file mode 100644 index 0000000..4d5b67c --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt @@ -0,0 +1,144 @@ +package com.stagehand.api.core + +import java.util.Optional +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class ValuesTest { + companion object { + private val NON_JSON = Any() + } + + enum class TestCase( + val value: JsonField<*>, + val expectedIsMissing: Boolean = false, + val expectedIsNull: Boolean = false, + val expectedAsKnown: Optional<*> = Optional.empty(), + val expectedAsBoolean: Optional = Optional.empty(), + val expectedAsNumber: Optional = Optional.empty(), + val expectedAsString: Optional = Optional.empty(), + val expectedAsArray: Optional> = Optional.empty(), + val expectedAsObject: Optional> = Optional.empty(), + ) { + MISSING(JsonMissing.of(), expectedIsMissing = true), + NULL(JsonNull.of(), expectedIsNull = true), + KNOWN(KnownValue.of(NON_JSON), expectedAsKnown = Optional.of(NON_JSON)), + KNOWN_BOOLEAN( + KnownValue.of(true), + expectedAsKnown = Optional.of(true), + expectedAsBoolean = Optional.of(true), + ), + BOOLEAN(JsonBoolean.of(true), expectedAsBoolean = Optional.of(true)), + KNOWN_NUMBER( + KnownValue.of(42), + expectedAsKnown = Optional.of(42), + expectedAsNumber = Optional.of(42), + ), + NUMBER(JsonNumber.of(42), expectedAsNumber = Optional.of(42)), + KNOWN_STRING( + KnownValue.of("hello"), + expectedAsKnown = Optional.of("hello"), + expectedAsString = Optional.of("hello"), + ), + STRING(JsonString.of("hello"), expectedAsString = Optional.of("hello")), + KNOWN_ARRAY_NOT_ALL_JSON( + KnownValue.of(listOf("a", "b", NON_JSON)), + expectedAsKnown = Optional.of(listOf("a", "b", NON_JSON)), + ), + KNOWN_ARRAY( + KnownValue.of(listOf("a", "b", "c")), + expectedAsKnown = Optional.of(listOf("a", "b", "c")), + expectedAsArray = + Optional.of(listOf(JsonString.of("a"), JsonString.of("b"), JsonString.of("c"))), + ), + ARRAY( + JsonArray.of(listOf(JsonString.of("a"), JsonString.of("b"), JsonString.of("c"))), + expectedAsArray = + Optional.of(listOf(JsonString.of("a"), JsonString.of("b"), JsonString.of("c"))), + ), + KNOWN_OBJECT_NOT_ALL_STRING_KEYS( + KnownValue.of(mapOf("a" to "b", 42 to "c")), + expectedAsKnown = Optional.of(mapOf("a" to "b", 42 to "c")), + ), + KNOWN_OBJECT_NOT_ALL_JSON( + KnownValue.of(mapOf("a" to "b", "b" to NON_JSON)), + expectedAsKnown = Optional.of(mapOf("a" to "b", "b" to NON_JSON)), + ), + KNOWN_OBJECT( + KnownValue.of(mapOf("a" to "b", "b" to "c")), + expectedAsKnown = Optional.of(mapOf("a" to "b", "b" to "c")), + expectedAsObject = + Optional.of(mapOf("a" to JsonString.of("b"), "b" to JsonString.of("c"))), + ), + OBJECT( + JsonObject.of(mapOf("a" to JsonString.of("b"), "b" to JsonString.of("c"))), + expectedAsObject = + Optional.of(mapOf("a" to JsonString.of("b"), "b" to JsonString.of("c"))), + ), + } + + @ParameterizedTest + @EnumSource + fun isMissing(testCase: TestCase) { + val isMissing = testCase.value.isMissing() + + assertThat(isMissing).isEqualTo(testCase.expectedIsMissing) + } + + @ParameterizedTest + @EnumSource + fun isNull(testCase: TestCase) { + val isNull = testCase.value.isNull() + + assertThat(isNull).isEqualTo(testCase.expectedIsNull) + } + + @ParameterizedTest + @EnumSource + fun asKnown(testCase: TestCase) { + val known = testCase.value.asKnown() + + assertThat(known).isEqualTo(testCase.expectedAsKnown) + } + + @ParameterizedTest + @EnumSource + fun asBoolean(testCase: TestCase) { + val boolean = testCase.value.asBoolean() + + assertThat(boolean).isEqualTo(testCase.expectedAsBoolean) + } + + @ParameterizedTest + @EnumSource + fun asNumber(testCase: TestCase) { + val number = testCase.value.asNumber() + + assertThat(number).isEqualTo(testCase.expectedAsNumber) + } + + @ParameterizedTest + @EnumSource + fun asString(testCase: TestCase) { + val string = testCase.value.asString() + + assertThat(string).isEqualTo(testCase.expectedAsString) + } + + @ParameterizedTest + @EnumSource + fun asArray(testCase: TestCase) { + val array = testCase.value.asArray() + + assertThat(array).isEqualTo(testCase.expectedAsArray) + } + + @ParameterizedTest + @EnumSource + fun asObject(testCase: TestCase) { + val obj = testCase.value.asObject() + + assertThat(obj).isEqualTo(testCase.expectedAsObject) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt new file mode 100644 index 0000000..f30d55c --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt @@ -0,0 +1,268 @@ +package com.stagehand.api.core.http + +import java.util.* +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import java.util.stream.Stream +import kotlin.streams.asStream +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.catchThrowable +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.* + +@ExtendWith(MockitoExtension::class) +internal class AsyncStreamResponseTest { + + companion object { + private val ERROR = RuntimeException("ERROR!") + } + + private val streamResponse = + spy> { + doReturn(Stream.of("chunk1", "chunk2", "chunk3")).whenever(it).stream() + } + private val erroringStreamResponse = + spy> { + doReturn( + sequence { + yield("chunk1") + yield("chunk2") + throw ERROR + } + .asStream() + ) + .whenever(it) + .stream() + } + private val executor = + spy { + doAnswer { invocation -> invocation.getArgument(0).run() } + .whenever(it) + .execute(any()) + } + private val handler = mock>() + + @Test + fun subscribe_whenAlreadySubscribed_throws() { + val asyncStreamResponse = CompletableFuture>().toAsync(executor) + asyncStreamResponse.subscribe {} + + val throwable = catchThrowable { asyncStreamResponse.subscribe {} } + + assertThat(throwable).isInstanceOf(IllegalStateException::class.java) + assertThat(throwable).hasMessage("Cannot subscribe more than once") + verify(executor, never()).execute(any()) + } + + @Test + fun subscribe_whenClosed_throws() { + val asyncStreamResponse = CompletableFuture>().toAsync(executor) + asyncStreamResponse.close() + + val throwable = catchThrowable { asyncStreamResponse.subscribe {} } + + assertThat(throwable).isInstanceOf(IllegalStateException::class.java) + assertThat(throwable).hasMessage("Cannot subscribe after the response is closed") + verify(executor, never()).execute(any()) + } + + @Test + fun subscribe_whenFutureCompletesAfterClose_doesNothing() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe(handler) + asyncStreamResponse.close() + + future.complete(streamResponse) + + verify(handler, never()).onNext(any()) + verify(handler, never()).onComplete(any()) + verify(executor, times(1)).execute(any()) + } + + @Test + fun subscribe_whenFutureErrors_callsOnComplete() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe(handler) + + future.completeExceptionally(ERROR) + + verify(handler, never()).onNext(any()) + verify(handler, times(1)).onComplete(Optional.of(ERROR)) + verify(executor, times(1)).execute(any()) + } + + @Test + fun subscribe_whenFutureCompletes_runsHandler() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe(handler) + + future.complete(streamResponse) + + inOrder(handler, streamResponse) { + verify(handler, times(1)).onNext("chunk1") + verify(handler, times(1)).onNext("chunk2") + verify(handler, times(1)).onNext("chunk3") + verify(handler, times(1)).onComplete(Optional.empty()) + verify(streamResponse, times(1)).close() + } + verify(executor, times(1)).execute(any()) + } + + @Test + fun subscribe_whenStreamErrors_callsOnCompleteEarly() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe(handler) + + future.complete(erroringStreamResponse) + + inOrder(handler, erroringStreamResponse) { + verify(handler, times(1)).onNext("chunk1") + verify(handler, times(1)).onNext("chunk2") + verify(handler, times(1)).onComplete(Optional.of(ERROR)) + verify(erroringStreamResponse, times(1)).close() + } + verify(executor, times(1)).execute(any()) + } + + @Test + fun onCompleteFuture_whenStreamResponseFutureNotCompleted_onCompleteFutureNotCompleted() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isNotCompleted + } + + @Test + fun onCompleteFuture_whenStreamResponseFutureErrors_onCompleteFutureCompletedExceptionally() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + future.completeExceptionally(ERROR) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isCompletedExceptionally + } + + @Test + fun onCompleteFuture_whenStreamResponseFutureCompletedButStillStreaming_onCompleteFutureNotCompleted() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + future.complete(streamResponse) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isNotCompleted + } + + @Test + fun onCompleteFuture_whenStreamResponseFutureCompletedAndStreamErrors_onCompleteFutureCompletedExceptionally() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe(handler) + future.complete(erroringStreamResponse) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isCompletedExceptionally + } + + @Test + fun onCompleteFuture_whenStreamResponseFutureCompletedAndStreamCompleted_onCompleteFutureCompleted() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe(handler) + future.complete(streamResponse) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isCompleted + } + + @Test + fun onCompleteFuture_whenHandlerOnCompleteWithoutThrowableThrows_onCompleteFutureCompleted() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe( + object : AsyncStreamResponse.Handler { + override fun onNext(value: String) {} + + override fun onComplete(error: Optional) = throw ERROR + } + ) + future.complete(streamResponse) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isCompleted + } + + @Test + fun onCompleteFuture_whenHandlerOnCompleteWithThrowableThrows_onCompleteFutureCompletedExceptionally() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.subscribe( + object : AsyncStreamResponse.Handler { + override fun onNext(value: String) {} + + override fun onComplete(error: Optional) = throw ERROR + } + ) + future.complete(erroringStreamResponse) + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isCompletedExceptionally + } + + @Test + fun onCompleteFuture_whenClosed_onCompleteFutureCompleted() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.close() + + val onCompletableFuture = asyncStreamResponse.onCompleteFuture() + + assertThat(onCompletableFuture).isCompleted + } + + @Test + fun close_whenNotClosed_closesStreamResponse() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + + asyncStreamResponse.close() + future.complete(streamResponse) + + verify(streamResponse, times(1)).close() + } + + @Test + fun close_whenAlreadyClosed_doesNothing() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.close() + future.complete(streamResponse) + + asyncStreamResponse.close() + + verify(streamResponse, times(1)).close() + } + + @Test + fun close_whenFutureErrors_doesNothing() { + val future = CompletableFuture>() + val asyncStreamResponse = future.toAsync(executor) + asyncStreamResponse.close() + + assertDoesNotThrow { future.completeExceptionally(ERROR) } + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt new file mode 100644 index 0000000..dae2b71 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt @@ -0,0 +1,242 @@ +package com.stagehand.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class HeadersTest { + + enum class TestCase( + val headers: Headers, + val expectedMap: Map>, + val expectedSize: Int, + ) { + EMPTY(Headers.builder().build(), expectedMap = mapOf(), expectedSize = 0), + PUT_ONE( + Headers.builder().put("name", "value").build(), + expectedMap = mapOf("name" to listOf("value")), + expectedSize = 1, + ), + PUT_MULTIPLE( + Headers.builder().put("name", listOf("value1", "value2")).build(), + expectedMap = mapOf("name" to listOf("value1", "value2")), + expectedSize = 2, + ), + MULTIPLE_PUT( + Headers.builder().put("name1", "value").put("name2", "value").build(), + expectedMap = mapOf("name1" to listOf("value"), "name2" to listOf("value")), + expectedSize = 2, + ), + MULTIPLE_PUT_SAME_NAME( + Headers.builder().put("name", "value1").put("name", "value2").build(), + expectedMap = mapOf("name" to listOf("value1", "value2")), + expectedSize = 2, + ), + MULTIPLE_PUT_MULTIPLE( + Headers.builder() + .put("name", listOf("value1", "value2")) + .put("name", listOf("value1", "value2")) + .build(), + expectedMap = mapOf("name" to listOf("value1", "value2", "value1", "value2")), + expectedSize = 4, + ), + PUT_CASE_INSENSITIVE( + Headers.builder() + .put("name", "value1") + .put("NAME", "value2") + .put("nAmE", "value3") + .build(), + expectedMap = mapOf("name" to listOf("value1", "value2", "value3")), + expectedSize = 3, + ), + PUT_ALL_MAP( + Headers.builder() + .putAll( + mapOf( + "name1" to listOf("value1", "value2"), + "name2" to listOf("value1", "value2"), + ) + ) + .build(), + expectedMap = + mapOf("name1" to listOf("value1", "value2"), "name2" to listOf("value1", "value2")), + expectedSize = 4, + ), + PUT_ALL_HEADERS( + Headers.builder().putAll(Headers.builder().put("name", "value").build()).build(), + expectedMap = mapOf("name" to listOf("value")), + expectedSize = 1, + ), + PUT_ALL_CASE_INSENSITIVE( + Headers.builder() + .putAll( + mapOf( + "name" to listOf("value1"), + "NAME" to listOf("value2"), + "nAmE" to listOf("value3"), + ) + ) + .build(), + expectedMap = mapOf("name" to listOf("value1", "value2", "value3")), + expectedSize = 3, + ), + REMOVE_ABSENT( + Headers.builder().remove("name").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_PRESENT_ONE( + Headers.builder().put("name", "value").remove("name").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_PRESENT_MULTIPLE( + Headers.builder().put("name", listOf("value1", "value2")).remove("name").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_CASE_INSENSITIVE( + Headers.builder().put("name", listOf("value1", "value2")).remove("NAME").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_ALL( + Headers.builder() + .put("name1", "value") + .put("name3", "value") + .removeAll(setOf("name1", "name2", "name3")) + .build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_ALL_CASE_INSENSITIVE( + Headers.builder() + .put("name1", "value") + .put("name3", "value") + .removeAll(setOf("NAME1", "nAmE3")) + .build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + CLEAR( + Headers.builder().put("name1", "value").put("name2", "value").clear().build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REPLACE_ONE_ABSENT( + Headers.builder().replace("name", "value").build(), + expectedMap = mapOf("name" to listOf("value")), + expectedSize = 1, + ), + REPLACE_ONE_PRESENT_ONE( + Headers.builder().put("name", "value1").replace("name", "value2").build(), + expectedMap = mapOf("name" to listOf("value2")), + expectedSize = 1, + ), + REPLACE_ONE_PRESENT_MULTIPLE( + Headers.builder() + .put("name", listOf("value1", "value2")) + .replace("name", "value3") + .build(), + expectedMap = mapOf("name" to listOf("value3")), + expectedSize = 1, + ), + REPLACE_MULTIPLE_ABSENT( + Headers.builder().replace("name", listOf("value1", "value2")).build(), + expectedMap = mapOf("name" to listOf("value1", "value2")), + expectedSize = 2, + ), + REPLACE_MULTIPLE_PRESENT_ONE( + Headers.builder() + .put("name", "value1") + .replace("name", listOf("value2", "value3")) + .build(), + expectedMap = mapOf("name" to listOf("value2", "value3")), + expectedSize = 2, + ), + REPLACE_MULTIPLE_PRESENT_MULTIPLE( + Headers.builder() + .put("name", listOf("value1", "value2")) + .replace("name", listOf("value3", "value4")) + .build(), + expectedMap = mapOf("name" to listOf("value3", "value4")), + expectedSize = 2, + ), + REPLACE_CASE_INSENSITIVE( + Headers.builder() + .put("name", "value1") + .replace("NAME", listOf("value2", "value3")) + .build(), + expectedMap = mapOf("NAME" to listOf("value2", "value3")), + expectedSize = 2, + ), + REPLACE_ALL_MAP( + Headers.builder() + .put("name1", "value1") + .put("name2", "value1") + .put("name3", "value1") + .replaceAll(mapOf("name1" to listOf("value2"), "name3" to listOf("value2"))) + .build(), + expectedMap = + mapOf( + "name1" to listOf("value2"), + "name2" to listOf("value1"), + "name3" to listOf("value2"), + ), + expectedSize = 3, + ), + REPLACE_ALL_HEADERS( + Headers.builder() + .put("name1", "value1") + .put("name2", "value1") + .put("name3", "value1") + .replaceAll(Headers.builder().put("name1", "value2").put("name3", "value2").build()) + .build(), + expectedMap = + mapOf( + "name1" to listOf("value2"), + "name2" to listOf("value1"), + "name3" to listOf("value2"), + ), + expectedSize = 3, + ), + REPLACE_ALL_CASE_INSENSITIVE( + Headers.builder() + .put("name1", "value1") + .put("name2", "value1") + .replaceAll(mapOf("NAME1" to listOf("value2"), "nAmE2" to listOf("value2"))) + .build(), + expectedMap = mapOf("NAME1" to listOf("value2"), "nAmE2" to listOf("value2")), + expectedSize = 2, + ), + } + + @ParameterizedTest + @EnumSource + fun namesAndValues(testCase: TestCase) { + val map = mutableMapOf>() + val headers = testCase.headers + headers.names().forEach { name -> map[name] = headers.values(name) } + + assertThat(map).isEqualTo(testCase.expectedMap) + } + + @ParameterizedTest + @EnumSource + fun caseInsensitiveNames(testCase: TestCase) { + val headers = testCase.headers + + for (name in headers.names()) { + assertThat(headers.values(name)).isEqualTo(headers.values(name.lowercase())) + assertThat(headers.values(name)).isEqualTo(headers.values(name.uppercase())) + } + } + + @ParameterizedTest + @EnumSource + fun size(testCase: TestCase) { + val size = testCase.headers.size + + assertThat(size).isEqualTo(testCase.expectedSize) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt new file mode 100644 index 0000000..1210beb --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt @@ -0,0 +1,180 @@ +package com.stagehand.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class QueryParamsTest { + + enum class TestCase( + val queryParams: QueryParams, + val expectedMap: Map>, + val expectedSize: Int, + ) { + EMPTY(QueryParams.builder().build(), expectedMap = mapOf(), expectedSize = 0), + PUT_ONE( + QueryParams.builder().put("key", "value").build(), + expectedMap = mapOf("key" to listOf("value")), + expectedSize = 1, + ), + PUT_MULTIPLE( + QueryParams.builder().put("key", listOf("value1", "value2")).build(), + expectedMap = mapOf("key" to listOf("value1", "value2")), + expectedSize = 2, + ), + MULTIPLE_PUT( + QueryParams.builder().put("key1", "value").put("key2", "value").build(), + expectedMap = mapOf("key1" to listOf("value"), "key2" to listOf("value")), + expectedSize = 2, + ), + MULTIPLE_PUT_SAME_NAME( + QueryParams.builder().put("key", "value1").put("key", "value2").build(), + expectedMap = mapOf("key" to listOf("value1", "value2")), + expectedSize = 2, + ), + MULTIPLE_PUT_MULTIPLE( + QueryParams.builder() + .put("key", listOf("value1", "value2")) + .put("key", listOf("value1", "value2")) + .build(), + expectedMap = mapOf("key" to listOf("value1", "value2", "value1", "value2")), + expectedSize = 4, + ), + PUT_ALL_MAP( + QueryParams.builder() + .putAll( + mapOf( + "key1" to listOf("value1", "value2"), + "key2" to listOf("value1", "value2"), + ) + ) + .build(), + expectedMap = + mapOf("key1" to listOf("value1", "value2"), "key2" to listOf("value1", "value2")), + expectedSize = 4, + ), + PUT_ALL_HEADERS( + QueryParams.builder().putAll(QueryParams.builder().put("key", "value").build()).build(), + expectedMap = mapOf("key" to listOf("value")), + expectedSize = 1, + ), + REMOVE_ABSENT( + QueryParams.builder().remove("key").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_PRESENT_ONE( + QueryParams.builder().put("key", "value").remove("key").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_PRESENT_MULTIPLE( + QueryParams.builder().put("key", listOf("value1", "value2")).remove("key").build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REMOVE_ALL( + QueryParams.builder() + .put("key1", "value") + .put("key3", "value") + .removeAll(setOf("key1", "key2", "key3")) + .build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + CLEAR( + QueryParams.builder().put("key1", "value").put("key2", "value").clear().build(), + expectedMap = mapOf(), + expectedSize = 0, + ), + REPLACE_ONE_ABSENT( + QueryParams.builder().replace("key", "value").build(), + expectedMap = mapOf("key" to listOf("value")), + expectedSize = 1, + ), + REPLACE_ONE_PRESENT_ONE( + QueryParams.builder().put("key", "value1").replace("key", "value2").build(), + expectedMap = mapOf("key" to listOf("value2")), + expectedSize = 1, + ), + REPLACE_ONE_PRESENT_MULTIPLE( + QueryParams.builder() + .put("key", listOf("value1", "value2")) + .replace("key", "value3") + .build(), + expectedMap = mapOf("key" to listOf("value3")), + expectedSize = 1, + ), + REPLACE_MULTIPLE_ABSENT( + QueryParams.builder().replace("key", listOf("value1", "value2")).build(), + expectedMap = mapOf("key" to listOf("value1", "value2")), + expectedSize = 2, + ), + REPLACE_MULTIPLE_PRESENT_ONE( + QueryParams.builder() + .put("key", "value1") + .replace("key", listOf("value2", "value3")) + .build(), + expectedMap = mapOf("key" to listOf("value2", "value3")), + expectedSize = 2, + ), + REPLACE_MULTIPLE_PRESENT_MULTIPLE( + QueryParams.builder() + .put("key", listOf("value1", "value2")) + .replace("key", listOf("value3", "value4")) + .build(), + expectedMap = mapOf("key" to listOf("value3", "value4")), + expectedSize = 2, + ), + REPLACE_ALL_MAP( + QueryParams.builder() + .put("key1", "value1") + .put("key2", "value1") + .put("key3", "value1") + .replaceAll(mapOf("key1" to listOf("value2"), "key3" to listOf("value2"))) + .build(), + expectedMap = + mapOf( + "key1" to listOf("value2"), + "key2" to listOf("value1"), + "key3" to listOf("value2"), + ), + expectedSize = 3, + ), + REPLACE_ALL_HEADERS( + QueryParams.builder() + .put("key1", "value1") + .put("key2", "value1") + .put("key3", "value1") + .replaceAll( + QueryParams.builder().put("key1", "value2").put("key3", "value2").build() + ) + .build(), + expectedMap = + mapOf( + "key1" to listOf("value2"), + "key2" to listOf("value1"), + "key3" to listOf("value2"), + ), + expectedSize = 3, + ), + } + + @ParameterizedTest + @EnumSource + fun keysAndValues(testCase: TestCase) { + val map = mutableMapOf>() + val queryParams = testCase.queryParams + queryParams.keys().forEach { key -> map[key] = queryParams.values(key) } + + assertThat(map).isEqualTo(testCase.expectedMap) + } + + @ParameterizedTest + @EnumSource + fun size(testCase: TestCase) { + val size = testCase.queryParams.size + + assertThat(size).isEqualTo(testCase.expectedSize) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt new file mode 100644 index 0000000..380321a --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt @@ -0,0 +1,356 @@ +package com.stagehand.api.core.http + +import com.github.tomakehurst.wiremock.client.WireMock.* +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import com.github.tomakehurst.wiremock.stubbing.Scenario +import com.stagehand.api.client.okhttp.OkHttpClient +import com.stagehand.api.core.RequestOptions +import com.stagehand.api.core.Sleeper +import com.stagehand.api.errors.StagehandRetryableException +import java.io.InputStream +import java.time.Duration +import java.util.concurrent.CompletableFuture +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.parallel.ResourceLock +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +@WireMockTest +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class RetryingHttpClientTest { + + private var openResponseCount = 0 + private lateinit var baseUrl: String + private lateinit var httpClient: HttpClient + + @BeforeEach + fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { + baseUrl = wmRuntimeInfo.httpBaseUrl + val okHttpClient = OkHttpClient.builder().build() + httpClient = + object : HttpClient { + + override fun execute( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse = trackClose(okHttpClient.execute(request, requestOptions)) + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture = + okHttpClient.executeAsync(request, requestOptions).thenApply { trackClose(it) } + + override fun close() = okHttpClient.close() + + private fun trackClose(response: HttpResponse): HttpResponse { + openResponseCount++ + return object : HttpResponse { + + private var isClosed = false + + override fun statusCode(): Int = response.statusCode() + + override fun headers(): Headers = response.headers() + + override fun body(): InputStream = response.body() + + override fun close() { + response.close() + if (isClosed) { + return + } + openResponseCount-- + isClosed = true + } + } + } + } + resetAllScenarios() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute(async: Boolean) { + stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) + val retryingClient = retryingHttpClientBuilder().build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + verify(1, postRequestedFor(urlPathEqualTo("/something"))) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withIdempotencyHeader(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .withHeader("X-Some-Header", matching("stainless-java-retry-.+")) + .willReturn(ok()) + ) + val retryingClient = + retryingHttpClientBuilder().maxRetries(2).idempotencyHeader("X-Some-Header").build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + verify(1, postRequestedFor(urlPathEqualTo("/something"))) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterHeader(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + // First we fail with a retry after header given as a date + .inScenario("foo") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT") + ) + .willSetStateTo("RETRY_AFTER_DATE") + ) + stubFor( + post(urlPathEqualTo("/something")) + // Then we fail with a retry after header given as a delay + .inScenario("foo") + .whenScenarioStateIs("RETRY_AFTER_DATE") + .willReturn(serviceUnavailable().withHeader("Retry-After", "1.234")) + .willSetStateTo("RETRY_AFTER_DELAY") + ) + stubFor( + post(urlPathEqualTo("/something")) + // Then we return a success + .inScenario("foo") + .whenScenarioStateIs("RETRY_AFTER_DELAY") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + verify( + 1, + postRequestedFor(urlPathEqualTo("/something")) + .withHeader("x-stainless-retry-count", equalTo("0")), + ) + verify( + 1, + postRequestedFor(urlPathEqualTo("/something")) + .withHeader("x-stainless-retry-count", equalTo("1")), + ) + verify( + 1, + postRequestedFor(urlPathEqualTo("/something")) + .withHeader("x-stainless-retry-count", equalTo("2")), + ) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withOverwrittenRetryCountHeader(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") // first we fail with a retry after header given as a date + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT") + ) + .willSetStateTo("RETRY_AFTER_DATE") + ) + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") // then we return a success + .whenScenarioStateIs("RETRY_AFTER_DATE") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .putHeader("x-stainless-retry-count", "42") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + verify( + 2, + postRequestedFor(urlPathEqualTo("/something")) + .withHeader("x-stainless-retry-count", equalTo("42")), + ) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterMsHeader(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn(serviceUnavailable().withHeader("Retry-After-Ms", "10")) + .willSetStateTo("RETRY_AFTER_DELAY") + ) + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") // then we return a success + .whenScenarioStateIs("RETRY_AFTER_DELAY") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val retryingClient = retryingHttpClientBuilder().maxRetries(1).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + verify(2, postRequestedFor(urlPathEqualTo("/something"))) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryableException(async: Boolean) { + stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) + + var callCount = 0 + val failingHttpClient = + object : HttpClient { + override fun execute( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse { + callCount++ + if (callCount == 1) { + throw StagehandRetryableException("Simulated retryable failure") + } + return httpClient.execute(request, requestOptions) + } + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture { + callCount++ + if (callCount == 1) { + val future = CompletableFuture() + future.completeExceptionally( + StagehandRetryableException("Simulated retryable failure") + ) + return future + } + return httpClient.executeAsync(request, requestOptions) + } + + override fun close() = httpClient.close() + } + + val retryingClient = + RetryingHttpClient.builder() + .httpClient(failingHttpClient) + .maxRetries(2) + .sleeper( + object : Sleeper { + + override fun sleep(duration: Duration) {} + + override fun sleepAsync(duration: Duration): CompletableFuture = + CompletableFuture.completedFuture(null) + + override fun close() {} + } + ) + .build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + verify( + 1, + postRequestedFor(urlPathEqualTo("/something")) + .withHeader("x-stainless-retry-count", equalTo("1")), + ) + verify( + 0, + postRequestedFor(urlPathEqualTo("/something")) + .withHeader("x-stainless-retry-count", equalTo("0")), + ) + assertNoResponseLeaks() + } + + private fun retryingHttpClientBuilder() = + RetryingHttpClient.builder() + .httpClient(httpClient) + // Use a no-op `Sleeper` to make the test fast. + .sleeper( + object : Sleeper { + + override fun sleep(duration: Duration) {} + + override fun sleepAsync(duration: Duration): CompletableFuture = + CompletableFuture.completedFuture(null) + + override fun close() {} + } + ) + + private fun HttpClient.execute(request: HttpRequest, async: Boolean): HttpResponse = + if (async) executeAsync(request).get() else execute(request) + + // When retrying, all failed responses should be closed. Only the final returned response should + // be open. + private fun assertNoResponseLeaks() = assertThat(openResponseCount).isEqualTo(1) +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt new file mode 100644 index 0000000..6928e9f --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt @@ -0,0 +1,47 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ActionTest { + + @Test + fun create() { + val action = + Action.builder() + .addArgument("string") + .description("description") + .method("method") + .selector("selector") + .backendNodeId(0L) + .build() + + assertThat(action.arguments()).containsExactly("string") + assertThat(action.description()).isEqualTo("description") + assertThat(action.method()).isEqualTo("method") + assertThat(action.selector()).isEqualTo("selector") + assertThat(action.backendNodeId()).contains(0L) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val action = + Action.builder() + .addArgument("string") + .description("description") + .method("method") + .selector("selector") + .backendNodeId(0L) + .build() + + val roundtrippedAction = + jsonMapper.readValue(jsonMapper.writeValueAsString(action), jacksonTypeRef()) + + assertThat(roundtrippedAction).isEqualTo(action) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt new file mode 100644 index 0000000..a1f75ab --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt @@ -0,0 +1,47 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ModelConfigTest { + + @Test + fun create() { + val modelConfig = + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + + assertThat(modelConfig.apiKey()).contains("apiKey") + assertThat(modelConfig.baseUrl()).contains("https://example.com") + assertThat(modelConfig.model()).contains("model") + assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val modelConfig = + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + + val roundtrippedModelConfig = + jsonMapper.readValue( + jsonMapper.writeValueAsString(modelConfig), + jacksonTypeRef(), + ) + + assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt new file mode 100644 index 0000000..921e718 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt @@ -0,0 +1,166 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionActParamsTest { + + @Test + fun create() { + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("click the sign in button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + .build() + } + + @Test + fun pathParams() { + val params = + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .input("click the sign in button") + .build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("click the sign in button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .input("click the sign in button") + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("click the sign in button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.input()) + .isEqualTo(SessionActParams.Input.ofString("click the sign in button")) + assertThat(body.frameId()).contains("frameId") + assertThat(body.options()) + .contains( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .input("click the sign in button") + .build() + + val body = params._body() + + assertThat(body.input()) + .isEqualTo(SessionActParams.Input.ofString("click the sign in button")) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt new file mode 100644 index 0000000..7723433 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt @@ -0,0 +1,69 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionActResponseTest { + + @Test + fun create() { + val sessionActResponse = + SessionActResponse.builder() + .addAction( + Action.builder() + .addArgument("string") + .description("description") + .method("method") + .selector("selector") + .backendNodeId(0L) + .build() + ) + .message("message") + .success(true) + .build() + + assertThat(sessionActResponse.actions()) + .containsExactly( + Action.builder() + .addArgument("string") + .description("description") + .method("method") + .selector("selector") + .backendNodeId(0L) + .build() + ) + assertThat(sessionActResponse.message()).isEqualTo("message") + assertThat(sessionActResponse.success()).isEqualTo(true) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionActResponse = + SessionActResponse.builder() + .addAction( + Action.builder() + .addArgument("string") + .description("description") + .method("method") + .selector("selector") + .backendNodeId(0L) + .build() + ) + .message("message") + .success(true) + .build() + + val roundtrippedSessionActResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionActResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionActResponse).isEqualTo(sessionActResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt new file mode 100644 index 0000000..914b7d4 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt @@ -0,0 +1,24 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionEndParamsTest { + + @Test + fun create() { + SessionEndParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + } + + @Test + fun pathParams() { + val params = + SessionEndParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt new file mode 100644 index 0000000..a5119d5 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionEndResponseTest { + + @Test + fun create() { + val sessionEndResponse = SessionEndResponse.builder().success(true).build() + + assertThat(sessionEndResponse.success()).contains(true) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionEndResponse = SessionEndResponse.builder().success(true).build() + + val roundtrippedSessionEndResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionEndResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionEndResponse).isEqualTo(sessionEndResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt new file mode 100644 index 0000000..532b194 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt @@ -0,0 +1,170 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.stagehand.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExecuteAgentParamsTest { + + @Test + fun create() { + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteAgentParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-4o") + .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .highlightCursor(true) + .maxSteps(10L) + .build() + ) + .frameId("frameId") + .build() + } + + @Test + fun pathParams() { + val params = + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .agentConfig(SessionExecuteAgentParams.AgentConfig.builder().build()) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .build() + ) + .build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteAgentParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-4o") + .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .highlightCursor(true) + .maxSteps(10L) + .build() + ) + .frameId("frameId") + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .agentConfig(SessionExecuteAgentParams.AgentConfig.builder().build()) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .build() + ) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteAgentParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-4o") + .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .highlightCursor(true) + .maxSteps(10L) + .build() + ) + .frameId("frameId") + .build() + + val body = params._body() + + assertThat(body.agentConfig()) + .isEqualTo( + SessionExecuteAgentParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-4o") + .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) + .systemPrompt("systemPrompt") + .build() + ) + assertThat(body.executeOptions()) + .isEqualTo( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .highlightCursor(true) + .maxSteps(10L) + .build() + ) + assertThat(body.frameId()).contains("frameId") + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .agentConfig(SessionExecuteAgentParams.AgentConfig.builder().build()) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .build() + ) + .build() + + val body = params._body() + + assertThat(body.agentConfig()) + .isEqualTo(SessionExecuteAgentParams.AgentConfig.builder().build()) + assertThat(body.executeOptions()) + .isEqualTo( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .build() + ) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt new file mode 100644 index 0000000..9da3901 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt @@ -0,0 +1,44 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.jsonMapper +import kotlin.jvm.optionals.getOrNull +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExecuteAgentResponseTest { + + @Test + fun create() { + val sessionExecuteAgentResponse = + SessionExecuteAgentResponse.builder() + .message("message") + .addStep(JsonValue.from(mapOf())) + .build() + + assertThat(sessionExecuteAgentResponse.message()).contains("message") + assertThat(sessionExecuteAgentResponse.steps().getOrNull()) + .containsExactly(JsonValue.from(mapOf())) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionExecuteAgentResponse = + SessionExecuteAgentResponse.builder() + .message("message") + .addStep(JsonValue.from(mapOf())) + .build() + + val roundtrippedSessionExecuteAgentResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExecuteAgentResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExecuteAgentResponse).isEqualTo(sessionExecuteAgentResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt new file mode 100644 index 0000000..67cdf9e --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt @@ -0,0 +1,158 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExtractParamsTest { + + @Test + fun create() { + SessionExtractParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("extract the page title") + .options( + SessionExtractParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + } + + @Test + fun pathParams() { + val params = + SessionExtractParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionExtractParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("extract the page title") + .options( + SessionExtractParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionExtractParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionExtractParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("extract the page title") + .options( + SessionExtractParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.frameId()).contains("frameId") + assertThat(body.instruction()).contains("extract the page title") + assertThat(body.options()) + .contains( + SessionExtractParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + assertThat(body.schema()) + .contains( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionExtractParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt new file mode 100644 index 0000000..22f62ea --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt @@ -0,0 +1,94 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.jsonMapper +import com.stagehand.api.errors.StagehandInvalidDataException +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class SessionExtractResponseTest { + + @Test + fun ofExtraction() { + val extraction = + SessionExtractResponse.Extraction.builder().extraction("extraction").build() + + val sessionExtractResponse = SessionExtractResponse.ofExtraction(extraction) + + assertThat(sessionExtractResponse.extraction()).contains(extraction) + assertThat(sessionExtractResponse.unionMember1()).isEmpty + } + + @Test + fun ofExtractionRoundtrip() { + val jsonMapper = jsonMapper() + val sessionExtractResponse = + SessionExtractResponse.ofExtraction( + SessionExtractResponse.Extraction.builder().extraction("extraction").build() + ) + + val roundtrippedSessionExtractResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExtractResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) + } + + @Test + fun ofUnionMember1() { + val unionMember1 = + SessionExtractResponse.UnionMember1.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + + val sessionExtractResponse = SessionExtractResponse.ofUnionMember1(unionMember1) + + assertThat(sessionExtractResponse.extraction()).isEmpty + assertThat(sessionExtractResponse.unionMember1()).contains(unionMember1) + } + + @Test + fun ofUnionMember1Roundtrip() { + val jsonMapper = jsonMapper() + val sessionExtractResponse = + SessionExtractResponse.ofUnionMember1( + SessionExtractResponse.UnionMember1.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + + val roundtrippedSessionExtractResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExtractResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) + } + + enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { + BOOLEAN(JsonValue.from(false)), + STRING(JsonValue.from("invalid")), + INTEGER(JsonValue.from(-1)), + FLOAT(JsonValue.from(3.14)), + ARRAY(JsonValue.from(listOf("invalid", "array"))), + } + + @ParameterizedTest + @EnumSource + fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { + val sessionExtractResponse = + jsonMapper().convertValue(testCase.value, jacksonTypeRef()) + + val e = assertThrows { sessionExtractResponse.validate() } + assertThat(e).hasMessageStartingWith("Unknown ") + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt new file mode 100644 index 0000000..6550c8e --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt @@ -0,0 +1,111 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.stagehand.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionNavigateParamsTest { + + @Test + fun create() { + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) + .build() + ) + .build() + } + + @Test + fun pathParams() { + val params = + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("https://example.com") + .build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) + .build() + ) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("https://example.com") + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.url()).isEqualTo("https://example.com") + assertThat(body.frameId()).contains("frameId") + assertThat(body.options()) + .contains( + SessionNavigateParams.Options.builder() + .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) + .build() + ) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .url("https://example.com") + .build() + + val body = params._body() + + assertThat(body.url()).isEqualTo("https://example.com") + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt new file mode 100644 index 0000000..2ba7257 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt @@ -0,0 +1,36 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionNavigateResponseTest { + + @Test + fun create() { + val sessionNavigateResponse = + SessionNavigateResponse.builder().ok(true).status(0L).url("url").build() + + assertThat(sessionNavigateResponse.ok()).contains(true) + assertThat(sessionNavigateResponse.status()).contains(0L) + assertThat(sessionNavigateResponse.url()).contains("url") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionNavigateResponse = + SessionNavigateResponse.builder().ok(true).status(0L).url("url").build() + + val roundtrippedSessionNavigateResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionNavigateResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionNavigateResponse).isEqualTo(sessionNavigateResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt new file mode 100644 index 0000000..6a3347f --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt @@ -0,0 +1,136 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.stagehand.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionObserveParamsTest { + + @Test + fun create() { + SessionObserveParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("instruction") + .options( + SessionObserveParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .build() + } + + @Test + fun pathParams() { + val params = + SessionObserveParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionObserveParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("instruction") + .options( + SessionObserveParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionObserveParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionObserveParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("instruction") + .options( + SessionObserveParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.frameId()).contains("frameId") + assertThat(body.instruction()).contains("instruction") + assertThat(body.options()) + .contains( + SessionObserveParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionObserveParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt new file mode 100644 index 0000000..9c70b5b --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt @@ -0,0 +1,66 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionStartParamsTest { + + @Test + fun create() { + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + } + + @Test + fun body() { + val params = + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + + val body = params._body() + + assertThat(body.env()).isEqualTo(SessionStartParams.Env.LOCAL) + assertThat(body.apiKey()).contains("apiKey") + assertThat(body.domSettleTimeout()).contains(0L) + assertThat(body.localBrowserLaunchOptions()) + .contains(SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build()) + assertThat(body.model()).contains("openai/gpt-4o") + assertThat(body.projectId()).contains("projectId") + assertThat(body.selfHeal()).contains(true) + assertThat(body.systemPrompt()).contains("systemPrompt") + assertThat(body.verbose()).contains(1L) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = SessionStartParams.builder().env(SessionStartParams.Env.LOCAL).build() + + val body = params._body() + + assertThat(body.env()).isEqualTo(SessionStartParams.Env.LOCAL) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt new file mode 100644 index 0000000..0ddd138 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt @@ -0,0 +1,42 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.models.sessions + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionStartResponseTest { + + @Test + fun create() { + val sessionStartResponse = + SessionStartResponse.builder() + .available(true) + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + assertThat(sessionStartResponse.available()).isEqualTo(true) + assertThat(sessionStartResponse.sessionId()) + .isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionStartResponse = + SessionStartResponse.builder() + .available(true) + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .build() + + val roundtrippedSessionStartResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionStartResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionStartResponse).isEqualTo(sessionStartResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt new file mode 100644 index 0000000..f35e2ad --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt @@ -0,0 +1,673 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services + +import com.github.tomakehurst.wiremock.client.WireMock.anyUrl +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.status +import com.github.tomakehurst.wiremock.client.WireMock.stubFor +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import com.stagehand.api.client.StagehandClient +import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.core.JsonValue +import com.stagehand.api.core.http.Headers +import com.stagehand.api.core.jsonMapper +import com.stagehand.api.errors.BadRequestException +import com.stagehand.api.errors.InternalServerException +import com.stagehand.api.errors.NotFoundException +import com.stagehand.api.errors.PermissionDeniedException +import com.stagehand.api.errors.RateLimitException +import com.stagehand.api.errors.StagehandException +import com.stagehand.api.errors.UnauthorizedException +import com.stagehand.api.errors.UnexpectedStatusCodeException +import com.stagehand.api.errors.UnprocessableEntityException +import com.stagehand.api.models.sessions.SessionStartParams +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.entry +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.parallel.ResourceLock + +@WireMockTest +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class ErrorHandlingTest { + + companion object { + + private val ERROR_JSON: JsonValue = JsonValue.from(mapOf("errorProperty" to "42")) + + private val ERROR_JSON_BYTES: ByteArray = jsonMapper().writeValueAsBytes(ERROR_JSON) + + private const val HEADER_NAME: String = "Error-Header" + + private const val HEADER_VALUE: String = "42" + + private const val NOT_JSON: String = "Not JSON" + } + + private lateinit var client: StagehandClient + + @BeforeEach + fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { + client = + StagehandOkHttpClient.builder() + .baseUrl(wmRuntimeInfo.httpBaseUrl) + .apiKey("My API Key") + .build() + } + + @Test + fun sessionsStart400() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(400).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(400) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart400WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(400).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(400) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart401() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(401).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(401) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart401WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(401).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(401) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart403() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(403).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(403) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart403WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(403).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(403) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart404() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(404).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(404) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart404WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(404).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(404) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart422() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(422).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(422) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart422WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(422).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(422) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart429() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(429).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(429) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart429WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(429).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(429) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart500() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(500).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(500) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart500WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(500).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(500) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart999() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn( + status(999).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(999) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStart999WithRawResponse() { + val sessionService = client.sessions().withRawResponse() + stubFor( + post(anyUrl()) + .willReturn( + status(999).withHeader(HEADER_NAME, HEADER_VALUE).withBody(ERROR_JSON_BYTES) + ) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e.statusCode()).isEqualTo(999) + assertThat(e.headers().toMap()).contains(entry(HEADER_NAME, listOf(HEADER_VALUE))) + assertThat(e.body()).isEqualTo(ERROR_JSON) + } + + @Test + fun sessionsStartInvalidJsonBody() { + val sessionService = client.sessions() + stubFor( + post(anyUrl()) + .willReturn(status(200).withHeader(HEADER_NAME, HEADER_VALUE).withBody(NOT_JSON)) + ) + + val e = + assertThrows { + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + } + + assertThat(e).hasMessage("Error reading response") + } + + private fun Headers.toMap(): Map> = + mutableMapOf>().also { map -> + names().forEach { map[it] = values(it) } + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt new file mode 100644 index 0000000..801d8ff --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt @@ -0,0 +1,71 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services + +import com.github.tomakehurst.wiremock.client.WireMock.anyUrl +import com.github.tomakehurst.wiremock.client.WireMock.equalTo +import com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath +import com.github.tomakehurst.wiremock.client.WireMock.ok +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor +import com.github.tomakehurst.wiremock.client.WireMock.stubFor +import com.github.tomakehurst.wiremock.client.WireMock.verify +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo +import com.github.tomakehurst.wiremock.junit5.WireMockTest +import com.stagehand.api.client.StagehandClient +import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.core.JsonValue +import com.stagehand.api.models.sessions.SessionStartParams +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.ResourceLock + +@WireMockTest +@ResourceLock("https://github.com/wiremock/wiremock/issues/169") +internal class ServiceParamsTest { + + private lateinit var client: StagehandClient + + @BeforeEach + fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { + client = + StagehandOkHttpClient.builder() + .baseUrl(wmRuntimeInfo.httpBaseUrl) + .apiKey("My API Key") + .build() + } + + @Disabled("Prism tests are disabled") + @Test + fun start() { + val sessionService = client.sessions() + stubFor(post(anyUrl()).willReturn(ok("{}"))) + + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .putAdditionalHeader("Secret-Header", "42") + .putAdditionalQueryParam("secret_query_param", "42") + .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) + .build() + ) + + verify( + postRequestedFor(anyUrl()) + .withHeader("Secret-Header", equalTo("42")) + .withQueryParam("secret_query_param", equalTo("42")) + .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) + ) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt new file mode 100644 index 0000000..49b568d --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt @@ -0,0 +1,262 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services.async + +import com.stagehand.api.TestServerExtension +import com.stagehand.api.client.okhttp.StagehandOkHttpClientAsync +import com.stagehand.api.core.JsonValue +import com.stagehand.api.models.sessions.ModelConfig +import com.stagehand.api.models.sessions.SessionActParams +import com.stagehand.api.models.sessions.SessionExecuteAgentParams +import com.stagehand.api.models.sessions.SessionExtractParams +import com.stagehand.api.models.sessions.SessionNavigateParams +import com.stagehand.api.models.sessions.SessionObserveParams +import com.stagehand.api.models.sessions.SessionStartParams +import kotlin.jvm.optionals.getOrNull +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class SessionServiceAsyncTest { + + @Disabled("Prism tests are disabled") + @Test + fun act() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.act( + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("click the sign in button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun end() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = sessionServiceAsync.end("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun executeAgent() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.executeAgent( + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteAgentParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-4o") + .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .highlightCursor(true) + .maxSteps(10L) + .build() + ) + .frameId("frameId") + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun extract() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.extract( + SessionExtractParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("extract the page title") + .options( + SessionExtractParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun navigate() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.navigate( + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) + .build() + ) + .build() + ) + + val response = responseFuture.get() + val unwrappedResponse = response.getOrNull() + unwrappedResponse?.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun observe() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val actionsFuture = + sessionServiceAsync.observe( + SessionObserveParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("instruction") + .options( + SessionObserveParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .build() + ) + + val actions = actionsFuture.get() + actions.forEach { it.validate() } + } + + @Disabled("Prism tests are disabled") + @Test + fun start() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + + val response = responseFuture.get() + response.validate() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt new file mode 100644 index 0000000..8b92fe7 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt @@ -0,0 +1,255 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.services.blocking + +import com.stagehand.api.TestServerExtension +import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.core.JsonValue +import com.stagehand.api.models.sessions.ModelConfig +import com.stagehand.api.models.sessions.SessionActParams +import com.stagehand.api.models.sessions.SessionExecuteAgentParams +import com.stagehand.api.models.sessions.SessionExtractParams +import com.stagehand.api.models.sessions.SessionNavigateParams +import com.stagehand.api.models.sessions.SessionObserveParams +import com.stagehand.api.models.sessions.SessionStartParams +import kotlin.jvm.optionals.getOrNull +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class SessionServiceTest { + + @Disabled("Prism tests are disabled") + @Test + fun act() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.act( + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("click the sign in button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun end() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val response = sessionService.end("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun executeAgent() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.executeAgent( + SessionExecuteAgentParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteAgentParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-4o") + .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteAgentParams.ExecuteOptions.builder() + .instruction("Find and click the first product") + .highlightCursor(true) + .maxSteps(10L) + .build() + ) + .frameId("frameId") + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun extract() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.extract( + SessionExtractParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("extract the page title") + .options( + SessionExtractParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun navigate() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.navigate( + SessionNavigateParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) + .build() + ) + .build() + ) + + val unwrappedResponse = response.getOrNull() + unwrappedResponse?.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun observe() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val actions = + sessionService.observe( + SessionObserveParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("instruction") + .options( + SessionObserveParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .selector("selector") + .timeout(0L) + .build() + ) + .build() + ) + + actions.forEach { it.validate() } + } + + @Disabled("Prism tests are disabled") + @Test + fun start() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.start( + SessionStartParams.builder() + .env(SessionStartParams.Env.LOCAL) + .apiKey("apiKey") + .domSettleTimeout(0L) + .localBrowserLaunchOptions( + SessionStartParams.LocalBrowserLaunchOptions.builder() + .headless(true) + .build() + ) + .model("openai/gpt-4o") + .projectId("projectId") + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(1L) + .build() + ) + + response.validate() + } +} diff --git a/stagehand-java-example/build.gradle.kts b/stagehand-java-example/build.gradle.kts new file mode 100644 index 0000000..baeb3f7 --- /dev/null +++ b/stagehand-java-example/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("stagehand.java") + application +} + +repositories { + mavenCentral() +} + +dependencies { + implementation(project(":stagehand-java")) +} + +tasks.withType().configureEach { + // Allow using more modern APIs, like `List.of` and `Map.of`, in examples. + options.release.set(9) +} + +application { + // Use `./gradlew :stagehand-java-example:run` to run `Main` + // Use `./gradlew :stagehand-java-example:run -Pexample=Something` to run `SomethingExample` + mainClass = "com.stagehand.api.example.${ + if (project.hasProperty("example")) + "${project.property("example")}Example" + else + "Main" + }" +} diff --git a/stagehand-java-lib/.keep b/stagehand-java-lib/.keep new file mode 100644 index 0000000..5e2c99f --- /dev/null +++ b/stagehand-java-lib/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store custom files to expand the SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/stagehand-java-proguard-test/build.gradle.kts b/stagehand-java-proguard-test/build.gradle.kts new file mode 100644 index 0000000..a4cde75 --- /dev/null +++ b/stagehand-java-proguard-test/build.gradle.kts @@ -0,0 +1,101 @@ +plugins { + id("stagehand.kotlin") + id("com.gradleup.shadow") version "8.3.8" +} + +buildscript { + repositories { + google() + } + + dependencies { + classpath("com.guardsquare:proguard-gradle:7.4.2") + classpath("com.android.tools:r8:8.3.37") + } +} + +dependencies { + testImplementation(project(":stagehand-java")) + testImplementation(kotlin("test")) + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") + testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") +} + +tasks.shadowJar { + from(sourceSets.test.get().output) + configurations = listOf(project.configurations.testRuntimeClasspath.get()) +} + +val proguardJarPath = "${layout.buildDirectory.get()}/libs/${project.name}-${project.version}-proguard.jar" +val proguardJar by tasks.registering(proguard.gradle.ProGuardTask::class) { + group = "verification" + dependsOn(tasks.shadowJar) + notCompatibleWithConfigurationCache("ProGuard") + + injars(tasks.shadowJar) + outjars(proguardJarPath) + printmapping("${layout.buildDirectory.get()}/proguard-mapping.txt") + + val javaHome = System.getProperty("java.home") + if (System.getProperty("java.version").startsWith("1.")) { + // Before Java 9, the runtime classes were packaged in a single jar file. + libraryjars("$javaHome/lib/rt.jar") + } else { + // As of Java 9, the runtime classes are packaged in modular jmod files. + libraryjars( + // Filters must be specified first, as a map. + mapOf("jarfilter" to "!**.jar", "filter" to "!module-info.class"), + "$javaHome/jmods/java.base.jmod" + ) + } + + configuration("./test.pro") + configuration("../stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro") +} + +val testProGuard by tasks.registering(JavaExec::class) { + group = "verification" + dependsOn(proguardJar) + notCompatibleWithConfigurationCache("ProGuard") + + mainClass.set("com.stagehand.api.proguard.ProGuardCompatibilityTest") + classpath = files(proguardJarPath) +} + +val r8JarPath = "${layout.buildDirectory.get()}/libs/${project.name}-${project.version}-r8.jar" +val r8Jar by tasks.registering(JavaExec::class) { + group = "verification" + dependsOn(tasks.shadowJar) + notCompatibleWithConfigurationCache("R8") + + mainClass.set("com.android.tools.r8.R8") + classpath = buildscript.configurations["classpath"] + + args = listOf( + "--release", + "--classfile", + "--output", r8JarPath, + "--lib", System.getProperty("java.home"), + "--pg-conf", "./test.pro", + "--pg-conf", "../stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro", + "--pg-map-output", "${layout.buildDirectory.get()}/r8-mapping.txt", + tasks.shadowJar.get().archiveFile.get().asFile.absolutePath, + ) +} + +val testR8 by tasks.registering(JavaExec::class) { + group = "verification" + dependsOn(r8Jar) + notCompatibleWithConfigurationCache("R8") + + mainClass.set("com.stagehand.api.proguard.ProGuardCompatibilityTest") + classpath = files(r8JarPath) +} + +tasks.test { + dependsOn(testProGuard) + dependsOn(testR8) + // We defer to the tests run via the ProGuard JAR. + enabled = false +} diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt new file mode 100644 index 0000000..13ad08e --- /dev/null +++ b/stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.stagehand.api.proguard + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.core.jsonMapper +import com.stagehand.api.models.sessions.Action +import com.stagehand.api.models.sessions.SessionExtractResponse +import kotlin.reflect.full.memberFunctions +import kotlin.reflect.jvm.javaMethod +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ProGuardCompatibilityTest { + + companion object { + + @JvmStatic + fun main(args: Array) { + // To debug that we're using the right JAR. + val jarPath = this::class.java.getProtectionDomain().codeSource.location + println("JAR being used: $jarPath") + + // We have to manually run the test methods instead of using the JUnit runner because it + // seems impossible to get working with R8. + val test = ProGuardCompatibilityTest() + test::class + .memberFunctions + .asSequence() + .filter { function -> + function.javaMethod?.isAnnotationPresent(Test::class.java) == true + } + .forEach { it.call(test) } + } + } + + @Test + fun proguardRules() { + val rulesFile = + javaClass.classLoader.getResourceAsStream("META-INF/proguard/stagehand-java-core.pro") + + assertThat(rulesFile).isNotNull() + } + + @Test + fun client() { + val client = StagehandOkHttpClient.builder().apiKey("My API Key").build() + + assertThat(client).isNotNull() + assertThat(client.sessions()).isNotNull() + } + + @Test + fun actionRoundtrip() { + val jsonMapper = jsonMapper() + val action = + Action.builder() + .addArgument("string") + .description("description") + .method("method") + .selector("selector") + .backendNodeId(0L) + .build() + + val roundtrippedAction = + jsonMapper.readValue(jsonMapper.writeValueAsString(action), jacksonTypeRef()) + + assertThat(roundtrippedAction).isEqualTo(action) + } + + @Test + fun sessionExtractResponseRoundtrip() { + val jsonMapper = jsonMapper() + val sessionExtractResponse = + SessionExtractResponse.ofExtraction( + SessionExtractResponse.Extraction.builder().extraction("extraction").build() + ) + + val roundtrippedSessionExtractResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExtractResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) + } +} diff --git a/stagehand-java-proguard-test/test.pro b/stagehand-java-proguard-test/test.pro new file mode 100644 index 0000000..3db213a --- /dev/null +++ b/stagehand-java-proguard-test/test.pro @@ -0,0 +1,9 @@ +# Specify the entrypoint where ProGuard starts to determine what's reachable. +-keep class com.stagehand.api.proguard.** { *; } + +# For the testing framework. +-keep class org.junit.** { *; } + +# Many warnings don't apply for our testing purposes. +-dontnote +-dontwarn \ No newline at end of file diff --git a/stagehand-java/build.gradle.kts b/stagehand-java/build.gradle.kts new file mode 100644 index 0000000..6d32486 --- /dev/null +++ b/stagehand-java/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + id("stagehand.kotlin") + id("stagehand.publish") +} + +dependencies { + api(project(":stagehand-java-client-okhttp")) +} + +// Redefine `dokkaJavadoc` to: +// - Depend on the root project's task for merging the docs of all the projects +// - Forward that task's output to this task's output +tasks.named("dokkaJavadoc").configure { + actions.clear() + + val dokkaJavadocCollector = rootProject.tasks["dokkaJavadocCollector"] + dependsOn(dokkaJavadocCollector) + + val outputDirectory = project.layout.buildDirectory.dir("dokka/javadoc") + doLast { + copy { + from(dokkaJavadocCollector.outputs.files) + into(outputDirectory) + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + } + + outputs.dir(outputDirectory) +} From d4a81325c0448e3b48c21c945666455d8356be83 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:24:50 +0000 Subject: [PATCH 002/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index b286614..8187e5b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 56543e7140dd04c5cc539051f40f0689 +config_hash: 3b8e0d3c5a985009ab97653e888f0354 From 87e557b7f61991fbee3d45a0c22d81a31dba443f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:24:58 +0000 Subject: [PATCH 003/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8187e5b..b242466 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 3b8e0d3c5a985009ab97653e888f0354 +config_hash: 11bbada11e4722208230ed2fab917d9e From 2d527b7014c3f91a584bde3339928438ce0461ae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:25:05 +0000 Subject: [PATCH 004/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index b242466..1714db7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 11bbada11e4722208230ed2fab917d9e +config_hash: 52dbd2eb1e28ad963e5a2bad9d550dc2 From 42ae8e115cffa5d14ee1dde2a2bc12358d3c178e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:25:12 +0000 Subject: [PATCH 005/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 1714db7..8bf0b37 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 52dbd2eb1e28ad963e5a2bad9d550dc2 +config_hash: b96a45d3fa353f5a8f5eb8027acad3ee From 0e54d12f68742d1ca73b89c1b09e31901145027f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:25:19 +0000 Subject: [PATCH 006/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8bf0b37..928b213 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: b96a45d3fa353f5a8f5eb8027acad3ee +config_hash: 5b4dff5d9fadb8695b4f266e2bab52f8 From 2a417021804e9c2188e241105d7693f9ab4faf6b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:25:26 +0000 Subject: [PATCH 007/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 928b213..406bd62 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 5b4dff5d9fadb8695b4f266e2bab52f8 +config_hash: 516b1f7051c6d71279f347541279821f From 7555f9dbe82295f648262a61273055a62d2419d8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:29:26 +0000 Subject: [PATCH 008/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 406bd62..acffb05 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 516b1f7051c6d71279f347541279821f +config_hash: 5f3345d1d825e49f896f3b0e493e6938 From 516842c2010f70aef03076d4ba0e9b6429ea643a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 18:37:25 +0000 Subject: [PATCH 009/164] feat(api): manual updates --- .github/workflows/publish-sonatype.yml | 41 ++++++++++++ .github/workflows/release-doctor.yml | 24 +++++++ .release-please-manifest.json | 3 + .stats.yml | 2 +- README.md | 14 +++- bin/check-release-environment | 33 +++++++++ build.gradle.kts | 2 +- .../main/kotlin/stagehand.publish.gradle.kts | 6 +- release-please-config.json | 67 +++++++++++++++++++ .../kotlin/com/stagehand/api/core/Check.kt | 2 +- 10 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/publish-sonatype.yml create mode 100644 .github/workflows/release-doctor.yml create mode 100644 .release-please-manifest.json create mode 100644 bin/check-release-environment create mode 100644 release-please-config.json diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml new file mode 100644 index 0000000..6a27d98 --- /dev/null +++ b/.github/workflows/publish-sonatype.yml @@ -0,0 +1,41 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to Sonatype in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/browserbase/stagehand-java/actions/workflows/publish-sonatype.yml +name: Publish Sonatype +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 8 + 21 + cache: gradle + + - name: Set up Gradle + uses: gradle/gradle-build-action@v2 + + - 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 publish --no-configuration-cache + env: + SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..a6e0235 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,24 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'browserbase/stagehand-java' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..1332969 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.1" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index acffb05..67a8e43 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 5f3345d1d825e49f896f3b0e493e6938 +config_hash: cb2b1795c195a63201c8ef7a617934d1 diff --git a/README.md b/README.md index 02a29e4..e2377af 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,26 @@ # Stagehand Java API Library + + [![Maven Central](https://img.shields.io/maven-central/v/com.stagehand.api/stagehand-java)](https://central.sonatype.com/artifact/com.stagehand.api/stagehand-java/0.0.1) [![javadoc](https://javadoc.io/badge2/com.stagehand.api/stagehand-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.stagehand.api/stagehand-java/0.0.1) + + The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://browserbase.com) from applications written in Java. It is generated with [Stainless](https://www.stainless.com/). + + The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.stagehand.api/stagehand-java/0.0.1). + + ## Installation + + ### Gradle ```kotlin @@ -27,6 +37,8 @@ implementation("com.stagehand.api:stagehand-java:0.0.1") ``` + + ## Requirements This library requires Java 8 or later. @@ -632,4 +644,4 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. -We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/stagehand-java/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/browserbase/stagehand-java/issues) with questions, bugs, or suggestions. diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..3a6a7b4 --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${SONATYPE_USERNAME}" ]; then + errors+=("The SONATYPE_USERNAME secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +if [ -z "${SONATYPE_PASSWORD}" ]; then + errors+=("The SONATYPE_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +if [ -z "${GPG_SIGNING_KEY}" ]; then + errors+=("The GPG_SIGNING_KEY secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +if [ -z "${GPG_SIGNING_PASSWORD}" ]; then + errors+=("The GPG_SIGNING_PASSWORD secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" diff --git a/build.gradle.kts b/build.gradle.kts index cca6e8a..5703c44 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.stagehand.api" - version = "0.0.1" + version = "0.0.1" // x-release-please-version } subprojects { diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index df771cd..326eeea 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -26,9 +26,9 @@ configure { } scm { - connection.set("scm:git:git://github.com/stainless-sdks/stagehand-java.git") - developerConnection.set("scm:git:git://github.com/stainless-sdks/stagehand-java.git") - url.set("https://github.com/stainless-sdks/stagehand-java") + connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + url.set("https://github.com/browserbase/stagehand-java") } versionMapping { diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..8f98719 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,67 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "simple", + "extra-files": [ + "README.md", + "build.gradle.kts" + ] +} \ No newline at end of file diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt index e61fae8..21ef979 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt +++ b/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt @@ -77,7 +77,7 @@ This can happen if you are either: Double-check that you are depending on compatible Jackson versions. -See https://www.github.com/stainless-sdks/stagehand-java#jackson for more information. +See https://www.github.com/browserbase/stagehand-java#jackson for more information. """ .trimIndent() } From 09a75534317622c7a9e14b99a83887aa473a05cc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:02:53 +0000 Subject: [PATCH 010/164] feat(api): tweak branding and fix some config fields --- .github/workflows/publish-sonatype.yml | 8 +- .github/workflows/release-doctor.yml | 8 +- .stats.yml | 2 +- LICENSE | 2 +- README.md | 195 +++++++++--------- SECURITY.md | 2 +- .../build.gradle.kts | 6 +- .../client/okhttp/BrowserbaseOkHttpClient.kt | 37 ++-- .../okhttp/BrowserbaseOkHttpClientAsync.kt | 37 ++-- .../api/client/okhttp/OkHttpClient.kt | 8 +- .../api/client/okhttp/OkHttpClientTest.kt | 0 .../build.gradle.kts | 6 +- .../stagehand/api/client/BrowserbaseClient.kt | 14 +- .../api/client/BrowserbaseClientAsync.kt | 13 +- .../api/client/BrowserbaseClientAsyncImpl.kt | 21 +- .../api/client/BrowserbaseClientImpl.kt | 20 +- .../stagehand/api/core/BaseDeserializer.kt | 0 .../com/stagehand/api/core/BaseSerializer.kt | 0 .../kotlin/com/stagehand/api/core/Check.kt | 0 .../com/stagehand/api/core/ClientOptions.kt | 60 +++--- .../com/stagehand/api/core/DefaultSleeper.kt | 0 .../com/stagehand/api/core/ObjectMappers.kt | 0 .../kotlin/com/stagehand/api/core/Params.kt | 0 .../stagehand/api/core/PhantomReachable.kt | 4 +- .../core/PhantomReachableExecutorService.kt | 0 .../api/core/PhantomReachableSleeper.kt | 0 .../com/stagehand/api/core/PrepareRequest.kt | 0 .../com/stagehand/api/core/Properties.kt | 4 +- .../com/stagehand/api/core/RequestOptions.kt | 0 .../kotlin/com/stagehand/api/core/Sleeper.kt | 0 .../kotlin/com/stagehand/api/core/Timeout.kt | 0 .../kotlin/com/stagehand/api/core/Utils.kt | 4 +- .../kotlin/com/stagehand/api/core/Values.kt | 12 +- .../api/core/handlers/ErrorHandler.kt | 0 .../api/core/handlers/JsonHandler.kt | 4 +- .../api/core/handlers/StringHandler.kt | 0 .../api/core/http/AsyncStreamResponse.kt | 0 .../com/stagehand/api/core/http/Headers.kt | 0 .../com/stagehand/api/core/http/HttpClient.kt | 0 .../com/stagehand/api/core/http/HttpMethod.kt | 0 .../stagehand/api/core/http/HttpRequest.kt | 0 .../api/core/http/HttpRequestBodies.kt | 6 +- .../api/core/http/HttpRequestBody.kt | 0 .../stagehand/api/core/http/HttpResponse.kt | 0 .../api/core/http/HttpResponseFor.kt | 0 ...ntomReachableClosingAsyncStreamResponse.kt | 0 .../http/PhantomReachableClosingHttpClient.kt | 0 .../PhantomReachableClosingStreamResponse.kt | 0 .../stagehand/api/core/http/QueryParams.kt | 0 .../api/core/http/RetryingHttpClient.kt | 8 +- .../stagehand/api/core/http/StreamResponse.kt | 0 .../api/errors/BadRequestException.kt | 2 +- .../api/errors/BrowserbaseException.kt | 2 +- .../errors/BrowserbaseInvalidDataException.kt | 5 +- .../api/errors/BrowserbaseIoException.kt | 5 +- .../errors/BrowserbaseRetryableException.kt | 5 +- .../api/errors/BrowserbaseServiceException.kt | 4 +- .../api/errors/InternalServerException.kt | 2 +- .../stagehand/api/errors/NotFoundException.kt | 2 +- .../api/errors/PermissionDeniedException.kt | 2 +- .../api/errors/RateLimitException.kt | 2 +- .../api/errors/UnauthorizedException.kt | 2 +- .../errors/UnexpectedStatusCodeException.kt | 2 +- .../errors/UnprocessableEntityException.kt | 2 +- .../stagehand/api/models/sessions/Action.kt | 14 +- .../api/models/sessions/ModelConfig.kt | 22 +- .../api/models/sessions/SessionActParams.kt | 42 ++-- .../api/models/sessions/SessionActResponse.kt | 10 +- .../api/models/sessions/SessionEndParams.kt | 0 .../api/models/sessions/SessionEndResponse.kt | 6 +- .../sessions/SessionExecuteAgentParams.kt | 62 +++--- .../sessions/SessionExecuteAgentResponse.kt | 8 +- .../models/sessions/SessionExtractParams.kt | 40 ++-- .../models/sessions/SessionExtractResponse.kt | 14 +- .../models/sessions/SessionNavigateParams.kt | 42 ++-- .../sessions/SessionNavigateResponse.kt | 10 +- .../models/sessions/SessionObserveParams.kt | 34 +-- .../api/models/sessions/SessionStartParams.kt | 54 ++--- .../models/sessions/SessionStartResponse.kt | 8 +- .../api/services/async/SessionServiceAsync.kt | 0 .../services/async/SessionServiceAsyncImpl.kt | 0 .../api/services/blocking/SessionService.kt | 0 .../services/blocking/SessionServiceImpl.kt | 0 .../proguard/browserbase-java-core.pro | 0 .../com/stagehand/api/TestServerExtension.kt | 0 .../stagehand/api/core/ClientOptionsTest.kt | 0 .../stagehand/api/core/ObjectMappersTest.kt | 0 .../api/core/PhantomReachableTest.kt | 0 .../com/stagehand/api/core/UtilsTest.kt | 0 .../com/stagehand/api/core/ValuesTest.kt | 0 .../api/core/http/AsyncStreamResponseTest.kt | 0 .../stagehand/api/core/http/HeadersTest.kt | 0 .../api/core/http/QueryParamsTest.kt | 0 .../api/core/http/RetryingHttpClientTest.kt | 6 +- .../api/models/sessions/ActionTest.kt | 0 .../api/models/sessions/ModelConfigTest.kt | 0 .../models/sessions/SessionActParamsTest.kt | 0 .../models/sessions/SessionActResponseTest.kt | 0 .../models/sessions/SessionEndParamsTest.kt | 0 .../models/sessions/SessionEndResponseTest.kt | 0 .../sessions/SessionExecuteAgentParamsTest.kt | 0 .../SessionExecuteAgentResponseTest.kt | 0 .../sessions/SessionExtractParamsTest.kt | 0 .../sessions/SessionExtractResponseTest.kt | 4 +- .../sessions/SessionNavigateParamsTest.kt | 0 .../sessions/SessionNavigateResponseTest.kt | 0 .../sessions/SessionObserveParamsTest.kt | 0 .../models/sessions/SessionStartParamsTest.kt | 0 .../sessions/SessionStartResponseTest.kt | 0 .../api/services/ErrorHandlingTest.kt | 12 +- .../api/services/ServiceParamsTest.kt | 8 +- .../services/async/SessionServiceAsyncTest.kt | 16 +- .../services/blocking/SessionServiceTest.kt | 16 +- browserbase-java-example/build.gradle.kts | 28 +++ browserbase-java-lib/.keep | 4 + .../build.gradle.kts | 8 +- .../api/proguard/ProGuardCompatibilityTest.kt | 6 +- .../test.pro | 0 .../build.gradle.kts | 6 +- build.gradle.kts | 2 +- ...gradle.kts => browserbase.java.gradle.kts} | 0 ...adle.kts => browserbase.kotlin.gradle.kts} | 2 +- ...dle.kts => browserbase.publish.gradle.kts} | 2 +- settings.gradle.kts | 4 +- 124 files changed, 527 insertions(+), 481 deletions(-) rename {stagehand-java-client-okhttp => browserbase-java-client-okhttp}/build.gradle.kts (76%) rename stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt => browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt (91%) rename stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt => browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt (90%) rename {stagehand-java-client-okhttp => browserbase-java-client-okhttp}/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt (96%) rename {stagehand-java-client-okhttp => browserbase-java-client-okhttp}/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/build.gradle.kts (93%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt (85%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt (87%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt (69%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt (69%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Check.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt (88%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Params.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt (92%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Properties.kt (88%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Sleeper.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Timeout.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Utils.kt (96%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/Values.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt (80%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/Headers.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt (96%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt (97%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt (82%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt (58%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt (61%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt (85%) rename stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt => browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt (80%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt (97%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt (93%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt (96%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt (96%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt (94%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt (94%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt (100%) rename stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro => browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/TestServerExtension.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt (98%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt (100%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt (98%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt (92%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt (95%) rename {stagehand-java-core => browserbase-java-core}/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt (95%) create mode 100644 browserbase-java-example/build.gradle.kts create mode 100644 browserbase-java-lib/.keep rename {stagehand-java-proguard-test => browserbase-java-proguard-test}/build.gradle.kts (90%) rename {stagehand-java-proguard-test => browserbase-java-proguard-test}/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt (93%) rename {stagehand-java-proguard-test => browserbase-java-proguard-test}/test.pro (100%) rename {stagehand-java => browserbase-java}/build.gradle.kts (85%) rename buildSrc/src/main/kotlin/{stagehand.java.gradle.kts => browserbase.java.gradle.kts} (100%) rename buildSrc/src/main/kotlin/{stagehand.kotlin.gradle.kts => browserbase.kotlin.gradle.kts} (99%) rename buildSrc/src/main/kotlin/{stagehand.publish.gradle.kts => browserbase.publish.gradle.kts} (97%) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 6a27d98..f40e546 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -35,7 +35,7 @@ jobs: GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')" ./gradlew publish --no-configuration-cache env: - SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file + SONATYPE_USERNAME: ${{ secrets.BROWSERBASE_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index a6e0235..aac0446 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -18,7 +18,7 @@ jobs: run: | bash ./bin/check-release-environment env: - SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.BROWSERBASE_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index 67a8e43..18b7af8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: cb2b1795c195a63201c8ef7a617934d1 +config_hash: 1548ab91b7e8621f7fa79e8cff0c3f93 diff --git a/LICENSE b/LICENSE index 6b24314..2cec9d4 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Stagehand + Copyright 2025 Browserbase Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index e2377af..9c68b67 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -# Stagehand Java API Library +# Browserbase Java API Library -[![Maven Central](https://img.shields.io/maven-central/v/com.stagehand.api/stagehand-java)](https://central.sonatype.com/artifact/com.stagehand.api/stagehand-java/0.0.1) -[![javadoc](https://javadoc.io/badge2/com.stagehand.api/stagehand-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.stagehand.api/stagehand-java/0.0.1) +[![Maven Central](https://img.shields.io/maven-central/v/com.stagehand.api/browserbase-java)](https://central.sonatype.com/artifact/com.stagehand.api/browserbase-java/0.0.1) +[![javadoc](https://javadoc.io/badge2/com.stagehand.api/browserbase-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.stagehand.api/browserbase-java/0.0.1) -The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://browserbase.com) from applications written in Java. +The Browserbase Java SDK provides convenient access to the [Browserbase REST API](https://browserbase.com) from applications written in Java. It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.stagehand.api/stagehand-java/0.0.1). +The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.stagehand.api/browserbase-java/0.0.1). @@ -24,7 +24,7 @@ The REST API documentation can be found on [browserbase.com](https://browserbase ### Gradle ```kotlin -implementation("com.stagehand.api:stagehand-java:0.0.1") +implementation("com.stagehand.api:browserbase-java:0.0.1") ``` ### Maven @@ -32,7 +32,7 @@ implementation("com.stagehand.api:stagehand-java:0.0.1") ```xml com.stagehand.api - stagehand-java + browserbase-java 0.0.1 ``` @@ -46,14 +46,14 @@ This library requires Java 8 or later. ## Usage ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; import com.stagehand.api.models.sessions.SessionStartParams; import com.stagehand.api.models.sessions.SessionStartResponse; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables -StagehandClient client = StagehandOkHttpClient.fromEnv(); +// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables +BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -66,21 +66,21 @@ SessionStartResponse response = client.sessions().start(params); Configure the client using system properties or environment variables: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables -StagehandClient client = StagehandOkHttpClient.fromEnv(); +// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables +BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); ``` Or manually: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .apiKey("My API Key") .build(); ``` @@ -88,12 +88,12 @@ StagehandClient client = StagehandOkHttpClient.builder() Or using a combination of the two approaches: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -StagehandClient client = StagehandOkHttpClient.builder() - // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties - // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() + // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties + // Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables .fromEnv() .apiKey("My API Key") .build(); @@ -101,10 +101,10 @@ StagehandClient client = StagehandOkHttpClient.builder() See this table for the available options: -| Setter | System property | Environment variable | Required | Default value | -| --------- | ------------------- | -------------------- | -------- | ---------------------------- | -| `apiKey` | `stagehand.apiKey` | `STAGEHAND_API_KEY` | false | - | -| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"http://localhost:3000/v1"` | +| Setter | System property | Environment variable | Required | Default value | +| --------- | ----------------------------- | ---------------------- | -------- | -------------------------------------------- | +| `apiKey` | `browserbase.stagehandApiKey` | `STAGEHAND_API_KEY` | true | - | +| `baseUrl` | `browserbase.baseUrl` | `BROWSERBASE_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | System properties take precedence over environment variables. @@ -117,9 +117,9 @@ System properties take precedence over environment variables. To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service: ```java -import com.stagehand.api.client.StagehandClient; +import com.stagehand.api.client.BrowserbaseClient; -StagehandClient clientWithOptions = client.withOptions(optionsBuilder -> { +BrowserbaseClient clientWithOptions = client.withOptions(optionsBuilder -> { optionsBuilder.baseUrl("https://example.com"); optionsBuilder.maxRetries(42); }); @@ -129,7 +129,7 @@ The `withOptions()` method does not affect the original client or service. ## Requests and responses -To send a request to the Stagehand API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. +To send a request to the Browserbase API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. For example, `client.sessions().start(...)` should be called with an instance of `SessionStartParams`, and it will return an instance of `SessionStartResponse`. @@ -146,15 +146,15 @@ Because each class is immutable, builder modification will _never_ affect alread The default client is synchronous. To switch to asynchronous execution, call the `async()` method: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; import com.stagehand.api.models.sessions.SessionStartParams; import com.stagehand.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables -StagehandClient client = StagehandOkHttpClient.fromEnv(); +// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables +BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -165,15 +165,15 @@ CompletableFuture response = client.async().sessions().sta Or create an asynchronous client from the beginning: ```java -import com.stagehand.api.client.StagehandClientAsync; -import com.stagehand.api.client.okhttp.StagehandOkHttpClientAsync; +import com.stagehand.api.client.BrowserbaseClientAsync; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClientAsync; import com.stagehand.api.models.sessions.SessionStartParams; import com.stagehand.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables -StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); +// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables +BrowserbaseClientAsync client = BrowserbaseOkHttpClientAsync.fromEnv(); SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -216,46 +216,46 @@ SessionStartResponse parsedResponse = response.parse(); The SDK throws custom unchecked exception types: -- [`StagehandServiceException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: +- [`BrowserbaseServiceException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: - | Status | Exception | - | ------ | -------------------------------------------------------------------------------------------------------------------------------- | - | 400 | [`BadRequestException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt) | - | 401 | [`UnauthorizedException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt) | - | 403 | [`PermissionDeniedException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt) | - | 404 | [`NotFoundException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt) | - | 422 | [`UnprocessableEntityException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt) | - | 429 | [`RateLimitException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt) | - | 5xx | [`InternalServerException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt) | - | others | [`UnexpectedStatusCodeException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt) | + | Status | Exception | + | ------ | ---------------------------------------------------------------------------------------------------------------------------------- | + | 400 | [`BadRequestException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt) | + | 401 | [`UnauthorizedException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt) | + | 403 | [`PermissionDeniedException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt) | + | 404 | [`NotFoundException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt) | + | 422 | [`UnprocessableEntityException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt) | + | 429 | [`RateLimitException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt) | + | 5xx | [`InternalServerException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt) | + | others | [`UnexpectedStatusCodeException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt) | -- [`StagehandIoException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt): I/O networking errors. +- [`BrowserbaseIoException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt): I/O networking errors. -- [`StagehandRetryableException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt): Generic error indicating a failure that could be retried by the client. +- [`BrowserbaseRetryableException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt): Generic error indicating a failure that could be retried by the client. -- [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. +- [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. -- [`StagehandException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. +- [`BrowserbaseException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. ## Logging The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). -Enable logging by setting the `STAGEHAND_LOG` environment variable to `info`: +Enable logging by setting the `BROWSERBASE_LOG` environment variable to `info`: ```sh -export STAGEHAND_LOG=info +export BROWSERBASE_LOG=info ``` Or to `debug` for more verbose logging: ```sh -export STAGEHAND_LOG=debug +export BROWSERBASE_LOG=debug ``` ## ProGuard and R8 -Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `stagehand-java-core` is published with a [configuration file](stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). +Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `browserbase-java-core` is published with a [configuration file](browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary. @@ -265,7 +265,7 @@ The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON seri The SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config). -If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt). +If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt). > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. @@ -289,10 +289,10 @@ The API may also explicitly instruct the SDK to retry or not retry a request. To set a custom number of retries, configure the client using the `maxRetries` method: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() .maxRetries(4) .build(); @@ -315,11 +315,11 @@ SessionStartResponse response = client.sessions().start( Or configure the default for all method calls at the client level: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; import java.time.Duration; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() .timeout(Duration.ofSeconds(30)) .build(); @@ -330,12 +330,12 @@ StagehandClient client = StagehandOkHttpClient.builder() To route requests through a proxy, configure the client using the `proxy` method: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; import java.net.InetSocketAddress; import java.net.Proxy; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() .proxy(new Proxy( Proxy.Type.HTTP, new InetSocketAddress( @@ -354,10 +354,10 @@ StagehandClient client = StagehandOkHttpClient.builder() To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa. .sslSocketFactory(yourSSLSocketFactory) @@ -371,12 +371,13 @@ StagehandClient client = StagehandOkHttpClient.builder() The SDK sends requests to the production by default. To send requests to a different environment, configure the client like so: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() - .environment1() + // Other options include `local` + .dev() .build(); ``` @@ -384,15 +385,15 @@ StagehandClient client = StagehandOkHttpClient.builder() The SDK consists of three artifacts: -- `stagehand-java-core` +- `browserbase-java-core` - Contains core SDK logic - Does not depend on [OkHttp](https://square.github.io/okhttp) - - Exposes [`StagehandClient`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt), [`StagehandClientAsync`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt), [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt), and [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), all of which can work with any HTTP client -- `stagehand-java-client-okhttp` + - Exposes [`BrowserbaseClient`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt), [`BrowserbaseClientAsync`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt), [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt), and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), all of which can work with any HTTP client +- `browserbase-java-client-okhttp` - Depends on [OkHttp](https://square.github.io/okhttp) - - Exposes [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) and [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt), which provide a way to construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt) and [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), respectively, using OkHttp -- `stagehand-java` - - Depends on and exposes the APIs of both `stagehand-java-core` and `stagehand-java-client-okhttp` + - Exposes [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) and [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), which provide a way to construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt) and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), respectively, using OkHttp +- `browserbase-java` + - Depends on and exposes the APIs of both `browserbase-java-core` and `browserbase-java-client-okhttp` - Does not have its own logic This structure allows replacing the SDK's default HTTP client without pulling in unnecessary dependencies. @@ -404,17 +405,17 @@ This structure allows replacing the SDK's default HTTP client without pulling in To use a customized `OkHttpClient`: -1. Replace your [`stagehand-java` dependency](#installation) with `stagehand-java-core` -2. Copy `stagehand-java-client-okhttp`'s [`OkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt) class into your code and customize it -3. Construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt) or [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), similarly to [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt), using your customized client +1. Replace your [`browserbase-java` dependency](#installation) with `browserbase-java-core` +2. Copy `browserbase-java-client-okhttp`'s [`OkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt) class into your code and customize it +3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your customized client ### Completely custom HTTP client To use a completely custom HTTP client: -1. Replace your [`stagehand-java` dependency](#installation) with `stagehand-java-core` -2. Write a class that implements the [`HttpClient`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt) interface -3. Construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt) or [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt), similarly to [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt), using your new client class +1. Replace your [`browserbase-java` dependency](#installation) with `browserbase-java-core` +2. Write a class that implements the [`HttpClient`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt) interface +3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your new client class ## Undocumented API functionality @@ -452,7 +453,7 @@ SessionStartParams params = SessionStartParams.builder() These properties can be accessed on the nested built object later using the `_additionalProperties()` method. -To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) object to its setter: +To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) object to its setter: ```java import com.stagehand.api.core.JsonValue; @@ -463,7 +464,7 @@ SessionStartParams params = SessionStartParams.builder() .build(); ``` -The most straightforward way to create a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) is using its `from(...)` method: +The most straightforward way to create a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) is using its `from(...)` method: ```java import com.stagehand.api.core.JsonValue; @@ -504,7 +505,7 @@ JsonValue complexValue = JsonValue.from(Map.of( Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. -To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt): +To forcibly omit a required parameter or property, pass [`JsonMissing`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt): ```java import com.stagehand.api.core.JsonMissing; @@ -574,7 +575,7 @@ if (env.isMissing()) { In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else. -By default, the SDK will not throw an exception in this case. It will throw [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt) only if you directly access the property. +By default, the SDK will not throw an exception in this case. It will throw [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt) only if you directly access the property. If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: @@ -597,10 +598,10 @@ SessionStartResponse response = client.sessions().start( Or configure the default for all method calls at the client level: ```java -import com.stagehand.api.client.StagehandClient; -import com.stagehand.api.client.okhttp.StagehandOkHttpClient; +import com.stagehand.api.client.BrowserbaseClient; +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -StagehandClient client = StagehandOkHttpClient.builder() +BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() .responseValidation(true) .build(); diff --git a/SECURITY.md b/SECURITY.md index dcfc419..be1c2db 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,7 +16,7 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Stagehand, please follow the respective company's security reporting guidelines. +or products provided by Browserbase, please follow the respective company's security reporting guidelines. --- diff --git a/stagehand-java-client-okhttp/build.gradle.kts b/browserbase-java-client-okhttp/build.gradle.kts similarity index 76% rename from stagehand-java-client-okhttp/build.gradle.kts rename to browserbase-java-client-okhttp/build.gradle.kts index cb49933..d5f5cb0 100644 --- a/stagehand-java-client-okhttp/build.gradle.kts +++ b/browserbase-java-client-okhttp/build.gradle.kts @@ -1,10 +1,10 @@ plugins { - id("stagehand.kotlin") - id("stagehand.publish") + id("browserbase.kotlin") + id("browserbase.publish") } dependencies { - api(project(":stagehand-java-core")) + api(project(":browserbase-java-core")) implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt b/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt similarity index 91% rename from stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt rename to browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt index 4b6805e..5113c2c 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClient.kt +++ b/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt @@ -3,8 +3,8 @@ package com.stagehand.api.client.okhttp import com.fasterxml.jackson.databind.json.JsonMapper -import com.stagehand.api.client.StagehandClient -import com.stagehand.api.client.StagehandClientImpl +import com.stagehand.api.client.BrowserbaseClient +import com.stagehand.api.client.BrowserbaseClientImpl import com.stagehand.api.core.ClientOptions import com.stagehand.api.core.Sleeper import com.stagehand.api.core.Timeout @@ -22,14 +22,14 @@ import javax.net.ssl.X509TrustManager import kotlin.jvm.optionals.getOrNull /** - * A class that allows building an instance of [StagehandClient] with [OkHttpClient] as the + * A class that allows building an instance of [BrowserbaseClient] with [OkHttpClient] as the * underlying [HttpClient]. */ -class StagehandOkHttpClient private constructor() { +class BrowserbaseOkHttpClient private constructor() { companion object { - /** Returns a mutable builder for constructing an instance of [StagehandClient]. */ + /** Returns a mutable builder for constructing an instance of [BrowserbaseClient]. */ @JvmStatic fun builder() = Builder() /** @@ -37,10 +37,10 @@ class StagehandOkHttpClient private constructor() { * * @see ClientOptions.Builder.fromEnv */ - @JvmStatic fun fromEnv(): StagehandClient = builder().fromEnv().build() + @JvmStatic fun fromEnv(): BrowserbaseClient = builder().fromEnv().build() } - /** A builder for [StagehandOkHttpClient]. */ + /** A builder for [BrowserbaseOkHttpClient]. */ class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() @@ -144,18 +144,22 @@ class StagehandOkHttpClient private constructor() { /** * The base URL to use for every request. * - * Defaults to the production environment: `http://localhost:3000/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. * * The following other environments, with dedicated builder methods, are available: - * - environment_1: `https://api.stagehand.browserbase.com/v1` + * - dev: `https://api.stagehand.dev.browserbase.com/v1` + * - local: `http://localhost:5000/v1` */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) - /** Sets [baseUrl] to `https://api.stagehand.browserbase.com/v1`. */ - fun environment1() = apply { clientOptions.environment1() } + /** Sets [baseUrl] to `https://api.stagehand.dev.browserbase.com/v1`. */ + fun dev() = apply { clientOptions.dev() } + + /** Sets [baseUrl] to `http://localhost:5000/v1`. */ + fun local() = apply { clientOptions.local() } /** * Whether to call `validate` on every response before returning it. @@ -201,10 +205,7 @@ class StagehandOkHttpClient private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } - fun apiKey(apiKey: String?) = apply { clientOptions.apiKey(apiKey) } - - /** Alias for calling [Builder.apiKey] with `apiKey.orElse(null)`. */ - fun apiKey(apiKey: Optional) = apiKey(apiKey.getOrNull()) + fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } @@ -294,12 +295,12 @@ class StagehandOkHttpClient private constructor() { fun fromEnv() = apply { clientOptions.fromEnv() } /** - * Returns an immutable instance of [StagehandClient]. + * Returns an immutable instance of [BrowserbaseClient]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): StagehandClient = - StagehandClientImpl( + fun build(): BrowserbaseClient = + BrowserbaseClientImpl( clientOptions .httpClient( OkHttpClient.builder() diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt b/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt similarity index 90% rename from stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt rename to browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt index e7a4c24..bf6ef08 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt @@ -3,8 +3,8 @@ package com.stagehand.api.client.okhttp import com.fasterxml.jackson.databind.json.JsonMapper -import com.stagehand.api.client.StagehandClientAsync -import com.stagehand.api.client.StagehandClientAsyncImpl +import com.stagehand.api.client.BrowserbaseClientAsync +import com.stagehand.api.client.BrowserbaseClientAsyncImpl import com.stagehand.api.core.ClientOptions import com.stagehand.api.core.Sleeper import com.stagehand.api.core.Timeout @@ -22,14 +22,14 @@ import javax.net.ssl.X509TrustManager import kotlin.jvm.optionals.getOrNull /** - * A class that allows building an instance of [StagehandClientAsync] with [OkHttpClient] as the + * A class that allows building an instance of [BrowserbaseClientAsync] with [OkHttpClient] as the * underlying [HttpClient]. */ -class StagehandOkHttpClientAsync private constructor() { +class BrowserbaseOkHttpClientAsync private constructor() { companion object { - /** Returns a mutable builder for constructing an instance of [StagehandClientAsync]. */ + /** Returns a mutable builder for constructing an instance of [BrowserbaseClientAsync]. */ @JvmStatic fun builder() = Builder() /** @@ -37,10 +37,10 @@ class StagehandOkHttpClientAsync private constructor() { * * @see ClientOptions.Builder.fromEnv */ - @JvmStatic fun fromEnv(): StagehandClientAsync = builder().fromEnv().build() + @JvmStatic fun fromEnv(): BrowserbaseClientAsync = builder().fromEnv().build() } - /** A builder for [StagehandOkHttpClientAsync]. */ + /** A builder for [BrowserbaseOkHttpClientAsync]. */ class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() @@ -144,18 +144,22 @@ class StagehandOkHttpClientAsync private constructor() { /** * The base URL to use for every request. * - * Defaults to the production environment: `http://localhost:3000/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. * * The following other environments, with dedicated builder methods, are available: - * - environment_1: `https://api.stagehand.browserbase.com/v1` + * - dev: `https://api.stagehand.dev.browserbase.com/v1` + * - local: `http://localhost:5000/v1` */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) - /** Sets [baseUrl] to `https://api.stagehand.browserbase.com/v1`. */ - fun environment1() = apply { clientOptions.environment1() } + /** Sets [baseUrl] to `https://api.stagehand.dev.browserbase.com/v1`. */ + fun dev() = apply { clientOptions.dev() } + + /** Sets [baseUrl] to `http://localhost:5000/v1`. */ + fun local() = apply { clientOptions.local() } /** * Whether to call `validate` on every response before returning it. @@ -201,10 +205,7 @@ class StagehandOkHttpClientAsync private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } - fun apiKey(apiKey: String?) = apply { clientOptions.apiKey(apiKey) } - - /** Alias for calling [Builder.apiKey] with `apiKey.orElse(null)`. */ - fun apiKey(apiKey: Optional) = apiKey(apiKey.getOrNull()) + fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } @@ -294,12 +295,12 @@ class StagehandOkHttpClientAsync private constructor() { fun fromEnv() = apply { clientOptions.fromEnv() } /** - * Returns an immutable instance of [StagehandClientAsync]. + * Returns an immutable instance of [BrowserbaseClientAsync]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): StagehandClientAsync = - StagehandClientAsyncImpl( + fun build(): BrowserbaseClientAsync = + BrowserbaseClientAsyncImpl( clientOptions .httpClient( OkHttpClient.builder() diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt b/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt similarity index 96% rename from stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt rename to browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt index 7db7941..14cfe6c 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt +++ b/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt @@ -8,7 +8,7 @@ import com.stagehand.api.core.http.HttpMethod import com.stagehand.api.core.http.HttpRequest import com.stagehand.api.core.http.HttpRequestBody import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.errors.StagehandIoException +import com.stagehand.api.errors.BrowserbaseIoException import java.io.IOException import java.io.InputStream import java.net.Proxy @@ -39,7 +39,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien return try { call.execute().toResponse() } catch (e: IOException) { - throw StagehandIoException("Request failed", e) + throw BrowserbaseIoException("Request failed", e) } finally { request.body?.close() } @@ -59,7 +59,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien } override fun onFailure(call: Call, e: IOException) { - future.completeExceptionally(StagehandIoException("Request failed", e)) + future.completeExceptionally(BrowserbaseIoException("Request failed", e)) } } ) @@ -84,7 +84,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien val clientBuilder = okHttpClient.newBuilder() val logLevel = - when (System.getenv("STAGEHAND_LOG")?.lowercase()) { + when (System.getenv("BROWSERBASE_LOG")?.lowercase()) { "info" -> HttpLoggingInterceptor.Level.BASIC "debug" -> HttpLoggingInterceptor.Level.BODY else -> null diff --git a/stagehand-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt b/browserbase-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt similarity index 100% rename from stagehand-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt rename to browserbase-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt diff --git a/stagehand-java-core/build.gradle.kts b/browserbase-java-core/build.gradle.kts similarity index 93% rename from stagehand-java-core/build.gradle.kts rename to browserbase-java-core/build.gradle.kts index 38bcf47..ca10c97 100644 --- a/stagehand-java-core/build.gradle.kts +++ b/browserbase-java-core/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("stagehand.kotlin") - id("stagehand.publish") + id("browserbase.kotlin") + id("browserbase.publish") } configurations.all { @@ -29,7 +29,7 @@ dependencies { implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") testImplementation(kotlin("test")) - testImplementation(project(":stagehand-java-client-okhttp")) + testImplementation(project(":browserbase-java-client-okhttp")) testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") testImplementation("org.assertj:assertj-core:3.25.3") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt similarity index 85% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt index bd37148..6e2b6a0 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClient.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt @@ -7,7 +7,7 @@ import com.stagehand.api.services.blocking.SessionService import java.util.function.Consumer /** - * A client for interacting with the Stagehand REST API synchronously. You can also switch to + * A client for interacting with the Browserbase REST API synchronously. You can also switch to * asynchronous execution via the [async] method. * * This client performs best when you create a single instance and reuse it for all interactions @@ -20,7 +20,7 @@ import java.util.function.Consumer * if you are writing an application that needs to aggressively release unused resources, then you * may call [close]. */ -interface StagehandClient { +interface BrowserbaseClient { /** * Returns a version of this client that uses asynchronous execution. @@ -28,7 +28,7 @@ interface StagehandClient { * The returned client shares its resources, like its connection pool and thread pools, with * this client. */ - fun async(): StagehandClientAsync + fun async(): BrowserbaseClientAsync /** * Returns a view of this service that provides access to raw HTTP responses for each method. @@ -40,7 +40,7 @@ interface StagehandClient { * * The original service is not modified. */ - fun withOptions(modifier: Consumer): StagehandClient + fun withOptions(modifier: Consumer): BrowserbaseClient fun sessions(): SessionService @@ -57,7 +57,7 @@ interface StagehandClient { */ fun close() - /** A view of [StagehandClient] that provides access to raw HTTP responses for each method. */ + /** A view of [BrowserbaseClient] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { /** @@ -65,7 +65,9 @@ interface StagehandClient { * * The original service is not modified. */ - fun withOptions(modifier: Consumer): StagehandClient.WithRawResponse + fun withOptions( + modifier: Consumer + ): BrowserbaseClient.WithRawResponse fun sessions(): SessionService.WithRawResponse } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt similarity index 87% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt index 078550d..aef1082 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsync.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt @@ -7,7 +7,7 @@ import com.stagehand.api.services.async.SessionServiceAsync import java.util.function.Consumer /** - * A client for interacting with the Stagehand REST API asynchronously. You can also switch to + * A client for interacting with the Browserbase REST API asynchronously. You can also switch to * synchronous execution via the [sync] method. * * This client performs best when you create a single instance and reuse it for all interactions @@ -20,7 +20,7 @@ import java.util.function.Consumer * if you are writing an application that needs to aggressively release unused resources, then you * may call [close]. */ -interface StagehandClientAsync { +interface BrowserbaseClientAsync { /** * Returns a version of this client that uses synchronous execution. @@ -28,7 +28,7 @@ interface StagehandClientAsync { * The returned client shares its resources, like its connection pool and thread pools, with * this client. */ - fun sync(): StagehandClient + fun sync(): BrowserbaseClient /** * Returns a view of this service that provides access to raw HTTP responses for each method. @@ -40,7 +40,7 @@ interface StagehandClientAsync { * * The original service is not modified. */ - fun withOptions(modifier: Consumer): StagehandClientAsync + fun withOptions(modifier: Consumer): BrowserbaseClientAsync fun sessions(): SessionServiceAsync @@ -58,7 +58,8 @@ interface StagehandClientAsync { fun close() /** - * A view of [StagehandClientAsync] that provides access to raw HTTP responses for each method. + * A view of [BrowserbaseClientAsync] that provides access to raw HTTP responses for each + * method. */ interface WithRawResponse { @@ -69,7 +70,7 @@ interface StagehandClientAsync { */ fun withOptions( modifier: Consumer - ): StagehandClientAsync.WithRawResponse + ): BrowserbaseClientAsync.WithRawResponse fun sessions(): SessionServiceAsync.WithRawResponse } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt similarity index 69% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt index 60cbec7..a7281d2 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientAsyncImpl.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt @@ -8,7 +8,8 @@ import com.stagehand.api.services.async.SessionServiceAsync import com.stagehand.api.services.async.SessionServiceAsyncImpl import java.util.function.Consumer -class StagehandClientAsyncImpl(private val clientOptions: ClientOptions) : StagehandClientAsync { +class BrowserbaseClientAsyncImpl(private val clientOptions: ClientOptions) : + BrowserbaseClientAsync { private val clientOptionsWithUserAgent = if (clientOptions.headers.names().contains("User-Agent")) clientOptions @@ -19,9 +20,9 @@ class StagehandClientAsyncImpl(private val clientOptions: ClientOptions) : Stage .build() // Pass the original clientOptions so that this client sets its own User-Agent. - private val sync: StagehandClient by lazy { StagehandClientImpl(clientOptions) } + private val sync: BrowserbaseClient by lazy { BrowserbaseClientImpl(clientOptions) } - private val withRawResponse: StagehandClientAsync.WithRawResponse by lazy { + private val withRawResponse: BrowserbaseClientAsync.WithRawResponse by lazy { WithRawResponseImpl(clientOptions) } @@ -29,19 +30,19 @@ class StagehandClientAsyncImpl(private val clientOptions: ClientOptions) : Stage SessionServiceAsyncImpl(clientOptionsWithUserAgent) } - override fun sync(): StagehandClient = sync + override fun sync(): BrowserbaseClient = sync - override fun withRawResponse(): StagehandClientAsync.WithRawResponse = withRawResponse + override fun withRawResponse(): BrowserbaseClientAsync.WithRawResponse = withRawResponse - override fun withOptions(modifier: Consumer): StagehandClientAsync = - StagehandClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + override fun withOptions(modifier: Consumer): BrowserbaseClientAsync = + BrowserbaseClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) override fun sessions(): SessionServiceAsync = sessions override fun close() = clientOptions.close() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - StagehandClientAsync.WithRawResponse { + BrowserbaseClientAsync.WithRawResponse { private val sessions: SessionServiceAsync.WithRawResponse by lazy { SessionServiceAsyncImpl.WithRawResponseImpl(clientOptions) @@ -49,8 +50,8 @@ class StagehandClientAsyncImpl(private val clientOptions: ClientOptions) : Stage override fun withOptions( modifier: Consumer - ): StagehandClientAsync.WithRawResponse = - StagehandClientAsyncImpl.WithRawResponseImpl( + ): BrowserbaseClientAsync.WithRawResponse = + BrowserbaseClientAsyncImpl.WithRawResponseImpl( clientOptions.toBuilder().apply(modifier::accept).build() ) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt similarity index 69% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt index 39ff1e2..afe65db 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/client/StagehandClientImpl.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt @@ -8,7 +8,7 @@ import com.stagehand.api.services.blocking.SessionService import com.stagehand.api.services.blocking.SessionServiceImpl import java.util.function.Consumer -class StagehandClientImpl(private val clientOptions: ClientOptions) : StagehandClient { +class BrowserbaseClientImpl(private val clientOptions: ClientOptions) : BrowserbaseClient { private val clientOptionsWithUserAgent = if (clientOptions.headers.names().contains("User-Agent")) clientOptions @@ -19,27 +19,27 @@ class StagehandClientImpl(private val clientOptions: ClientOptions) : StagehandC .build() // Pass the original clientOptions so that this client sets its own User-Agent. - private val async: StagehandClientAsync by lazy { StagehandClientAsyncImpl(clientOptions) } + private val async: BrowserbaseClientAsync by lazy { BrowserbaseClientAsyncImpl(clientOptions) } - private val withRawResponse: StagehandClient.WithRawResponse by lazy { + private val withRawResponse: BrowserbaseClient.WithRawResponse by lazy { WithRawResponseImpl(clientOptions) } private val sessions: SessionService by lazy { SessionServiceImpl(clientOptionsWithUserAgent) } - override fun async(): StagehandClientAsync = async + override fun async(): BrowserbaseClientAsync = async - override fun withRawResponse(): StagehandClient.WithRawResponse = withRawResponse + override fun withRawResponse(): BrowserbaseClient.WithRawResponse = withRawResponse - override fun withOptions(modifier: Consumer): StagehandClient = - StagehandClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + override fun withOptions(modifier: Consumer): BrowserbaseClient = + BrowserbaseClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) override fun sessions(): SessionService = sessions override fun close() = clientOptions.close() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - StagehandClient.WithRawResponse { + BrowserbaseClient.WithRawResponse { private val sessions: SessionService.WithRawResponse by lazy { SessionServiceImpl.WithRawResponseImpl(clientOptions) @@ -47,8 +47,8 @@ class StagehandClientImpl(private val clientOptions: ClientOptions) : StagehandC override fun withOptions( modifier: Consumer - ): StagehandClient.WithRawResponse = - StagehandClientImpl.WithRawResponseImpl( + ): BrowserbaseClient.WithRawResponse = + BrowserbaseClientImpl.WithRawResponseImpl( clientOptions.toBuilder().apply(modifier::accept).build() ) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt similarity index 88% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt index 50b2df9..3cbfa6e 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt @@ -20,7 +20,7 @@ private constructor( /** * The HTTP client to use in the SDK. * - * Use the one published in `stagehand-java-client-okhttp` or implement your own. + * Use the one published in `browserbase-java-client-okhttp` or implement your own. * * This class takes ownership of the client and closes it when closed. */ @@ -93,7 +93,7 @@ private constructor( * Defaults to 2. */ @get:JvmName("maxRetries") val maxRetries: Int, - private val apiKey: String?, + @get:JvmName("apiKey") val apiKey: String, ) { init { @@ -105,22 +105,23 @@ private constructor( /** * The base URL to use for every request. * - * Defaults to the production environment: `http://localhost:3000/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. * * The following other environments, with dedicated builder methods, are available: - * - environment_1: `https://api.stagehand.browserbase.com/v1` + * - dev: `https://api.stagehand.dev.browserbase.com/v1` + * - local: `http://localhost:5000/v1` */ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL - fun apiKey(): Optional = Optional.ofNullable(apiKey) - fun toBuilder() = Builder().from(this) companion object { - const val PRODUCTION_URL = "http://localhost:3000/v1" + const val PRODUCTION_URL = "https://api.stagehand.browserbase.com/v1" + + const val DEV_URL = "https://api.stagehand.dev.browserbase.com/v1" - const val ENVIRONMENT_1_URL = "https://api.stagehand.browserbase.com/v1" + const val LOCAL_URL = "http://localhost:5000/v1" /** * Returns a mutable builder for constructing an instance of [ClientOptions]. @@ -128,6 +129,7 @@ private constructor( * The following fields are required: * ```java * .httpClient() + * .apiKey() * ``` */ @JvmStatic fun builder() = Builder() @@ -175,7 +177,7 @@ private constructor( /** * The HTTP client to use in the SDK. * - * Use the one published in `stagehand-java-client-okhttp` or implement your own. + * Use the one published in `browserbase-java-client-okhttp` or implement your own. * * This class takes ownership of the client and closes it when closed. */ @@ -225,18 +227,22 @@ private constructor( /** * The base URL to use for every request. * - * Defaults to the production environment: `http://localhost:3000/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. * * The following other environments, with dedicated builder methods, are available: - * - environment_1: `https://api.stagehand.browserbase.com/v1` + * - dev: `https://api.stagehand.dev.browserbase.com/v1` + * - local: `http://localhost:5000/v1` */ fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl } /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) - /** Sets [baseUrl] to `https://api.stagehand.browserbase.com/v1`. */ - fun environment1() = baseUrl(ENVIRONMENT_1_URL) + /** Sets [baseUrl] to `https://api.stagehand.dev.browserbase.com/v1`. */ + fun dev() = baseUrl(DEV_URL) + + /** Sets [baseUrl] to `http://localhost:5000/v1`. */ + fun local() = baseUrl(LOCAL_URL) /** * Whether to call `validate` on every response before returning it. @@ -282,10 +288,7 @@ private constructor( */ fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } - fun apiKey(apiKey: String?) = apply { this.apiKey = apiKey } - - /** Alias for calling [Builder.apiKey] with `apiKey.orElse(null)`. */ - fun apiKey(apiKey: Optional) = apiKey(apiKey.getOrNull()) + fun apiKey(apiKey: String) = apply { this.apiKey = apiKey } fun headers(headers: Headers) = apply { this.headers.clear() @@ -374,20 +377,19 @@ private constructor( * * See this table for the available options: * - * |Setter |System property |Environment variable|Required|Default value | - * |---------|-------------------|--------------------|--------|----------------------------| - * |`apiKey` |`stagehand.apiKey` |`STAGEHAND_API_KEY` |false |- | - * |`baseUrl`|`stagehand.baseUrl`|`STAGEHAND_BASE_URL`|true |`"http://localhost:3000/v1"`| + * |Setter |System property |Environment variable |Required|Default value | + * |---------|-----------------------------|----------------------|--------|--------------------------------------------| + * |`apiKey` |`browserbase.stagehandApiKey`|`STAGEHAND_API_KEY` |true |- | + * |`baseUrl`|`browserbase.baseUrl` |`BROWSERBASE_BASE_URL`|true |`"https://api.stagehand.browserbase.com/v1"`| * * System properties take precedence over environment variables. */ fun fromEnv() = apply { - (System.getProperty("stagehand.baseUrl") ?: System.getenv("STAGEHAND_BASE_URL"))?.let { - baseUrl(it) - } - (System.getProperty("stagehand.apiKey") ?: System.getenv("STAGEHAND_API_KEY"))?.let { - apiKey(it) - } + (System.getProperty("browserbase.baseUrl") ?: System.getenv("BROWSERBASE_BASE_URL")) + ?.let { baseUrl(it) } + (System.getProperty("browserbase.stagehandApiKey") + ?: System.getenv("STAGEHAND_API_KEY")) + ?.let { apiKey(it) } } /** @@ -398,6 +400,7 @@ private constructor( * The following fields are required: * ```java * .httpClient() + * .apiKey() * ``` * * @throws IllegalStateException if any required field is unset. @@ -405,6 +408,7 @@ private constructor( fun build(): ClientOptions { val httpClient = checkRequired("httpClient", httpClient) val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) + val apiKey = checkRequired("apiKey", apiKey) val headers = Headers.builder() val queryParams = QueryParams.builder() @@ -415,7 +419,7 @@ private constructor( headers.put("X-Stainless-Package-Version", getPackageVersion()) headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) - apiKey?.let { + apiKey.let { if (!it.isEmpty()) { headers.put("Authorization", "Bearer $it") } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt similarity index 92% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt index 48c4eb3..648e916 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt @@ -2,7 +2,7 @@ package com.stagehand.api.core -import com.stagehand.api.errors.StagehandException +import com.stagehand.api.errors.BrowserbaseException import java.lang.reflect.InvocationTargetException /** @@ -46,7 +46,7 @@ private val closeWhenPhantomReachable: ((Any, () -> Unit) -> Unit)? by lazy { is Error -> throw cause } } - throw StagehandException("Unexpected reflective invocation failure", e) + throw BrowserbaseException("Unexpected reflective invocation failure", e) } } } catch (e: ReflectiveOperationException) { diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt similarity index 88% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt index f2e9de2..d24ffbe 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt @@ -2,7 +2,7 @@ package com.stagehand.api.core -import com.stagehand.api.client.StagehandClient +import com.stagehand.api.client.BrowserbaseClient fun getOsArch(): String { val osArch = System.getProperty("os.arch") @@ -37,6 +37,6 @@ fun getOsName(): String { fun getOsVersion(): String = System.getProperty("os.version", "unknown") fun getPackageVersion(): String = - StagehandClient::class.java.`package`.implementationVersion ?: "unknown" + BrowserbaseClient::class.java.`package`.implementationVersion ?: "unknown" fun getJavaVersion(): String = System.getProperty("java.version", "unknown") diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt similarity index 96% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt index 7e8118b..1e35e53 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt @@ -2,7 +2,7 @@ package com.stagehand.api.core -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.SortedMap import java.util.concurrent.CompletableFuture @@ -10,7 +10,7 @@ import java.util.concurrent.locks.Lock @JvmSynthetic internal fun T?.getOrThrow(name: String): T = - this ?: throw StagehandInvalidDataException("`${name}` is not present") + this ?: throw BrowserbaseInvalidDataException("`${name}` is not present") @JvmSynthetic internal fun List.toImmutable(): List = diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt index 8410d97..e772b85 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt @@ -24,7 +24,7 @@ import com.fasterxml.jackson.databind.node.JsonNodeType.OBJECT import com.fasterxml.jackson.databind.node.JsonNodeType.POJO import com.fasterxml.jackson.databind.node.JsonNodeType.STRING import com.fasterxml.jackson.databind.ser.std.NullSerializer -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.io.InputStream import java.util.Objects import java.util.Optional @@ -108,7 +108,7 @@ sealed class JsonField { } fun asStringOrThrow(): String = - asString().orElseThrow { StagehandInvalidDataException("Value is not a string") } + asString().orElseThrow { BrowserbaseInvalidDataException("Value is not a string") } /** * Returns an [Optional] containing this field's list value, or an empty [Optional] if it @@ -171,9 +171,9 @@ sealed class JsonField { internal fun getRequired(name: String): T = when (this) { is KnownValue -> value - is JsonMissing -> throw StagehandInvalidDataException("`$name` is not set") - is JsonNull -> throw StagehandInvalidDataException("`$name` is null") - else -> throw StagehandInvalidDataException("`$name` is invalid, received $this") + is JsonMissing -> throw BrowserbaseInvalidDataException("`$name` is not set") + is JsonNull -> throw BrowserbaseInvalidDataException("`$name` is null") + else -> throw BrowserbaseInvalidDataException("`$name` is invalid, received $this") } @JvmSynthetic @@ -188,7 +188,7 @@ sealed class JsonField { is KnownValue -> Optional.of(value) is JsonMissing, is JsonNull -> Optional.empty() - else -> throw StagehandInvalidDataException("`$name` is invalid, received $this") + else -> throw BrowserbaseInvalidDataException("`$name` is invalid, received $this") } @JvmSynthetic diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt similarity index 80% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt index dc8d9e5..5ab311e 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.stagehand.api.core.http.HttpResponse import com.stagehand.api.core.http.HttpResponse.Handler -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException @JvmSynthetic internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler = @@ -15,6 +15,6 @@ internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler try { jsonMapper.readValue(response.body(), jacksonTypeRef()) } catch (e: Exception) { - throw StagehandInvalidDataException("Error reading response", e) + throw BrowserbaseInvalidDataException("Error reading response", e) } } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt similarity index 96% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt index 98811cc..0066e15 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt @@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.node.JsonNodeType import com.stagehand.api.core.MultipartField -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.io.InputStream import java.io.OutputStream import kotlin.jvm.optionals.getOrNull @@ -97,7 +97,7 @@ internal fun multipartFormData( JsonNodeType.ARRAY, JsonNodeType.OBJECT, JsonNodeType.POJO -> - throw StagehandInvalidDataException( + throw BrowserbaseInvalidDataException( "Unexpected JsonNode type in array: ${node.nodeType}" ) } @@ -111,7 +111,7 @@ internal fun multipartFormData( } JsonNodeType.POJO, null -> - throw StagehandInvalidDataException( + throw BrowserbaseInvalidDataException( "Unexpected JsonNode type: ${node.nodeType}" ) } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt index c23a398..688ae4f 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt @@ -4,8 +4,8 @@ import com.stagehand.api.core.DefaultSleeper import com.stagehand.api.core.RequestOptions import com.stagehand.api.core.Sleeper import com.stagehand.api.core.checkRequired -import com.stagehand.api.errors.StagehandIoException -import com.stagehand.api.errors.StagehandRetryableException +import com.stagehand.api.errors.BrowserbaseIoException +import com.stagehand.api.errors.BrowserbaseRetryableException import java.io.IOException import java.time.Clock import java.time.Duration @@ -182,8 +182,8 @@ private constructor( private fun shouldRetry(throwable: Throwable): Boolean = // Only retry known retryable exceptions, other exceptions are not intended to be retried. throwable is IOException || - throwable is StagehandIoException || - throwable is StagehandRetryableException + throwable is BrowserbaseIoException || + throwable is BrowserbaseRetryableException private fun getRetryBackoffDuration(retries: Int, response: HttpResponse?): Duration { // About the Retry-After header: diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt index 3e34a60..0df8b4a 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class BadRequestException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("400: $body", cause) { + BrowserbaseServiceException("400: $body", cause) { override fun statusCode(): Int = 400 diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt similarity index 82% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt index 0d0087f..eb7f6e5 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt @@ -1,5 +1,5 @@ package com.stagehand.api.errors -open class StagehandException +open class BrowserbaseException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt similarity index 58% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt index 3d7fb03..8e9730d 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandInvalidDataException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt @@ -1,5 +1,6 @@ package com.stagehand.api.errors -class StagehandInvalidDataException +class BrowserbaseInvalidDataException @JvmOverloads -constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) +constructor(message: String? = null, cause: Throwable? = null) : + BrowserbaseException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt similarity index 61% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt index 4080af1..aa9c0de 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandIoException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt @@ -1,5 +1,6 @@ package com.stagehand.api.errors -class StagehandIoException +class BrowserbaseIoException @JvmOverloads -constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) +constructor(message: String? = null, cause: Throwable? = null) : + BrowserbaseException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt similarity index 85% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt index 252b6c6..8984d2e 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandRetryableException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt @@ -9,6 +9,7 @@ package com.stagehand.api.errors * @param message A descriptive error message * @param cause The underlying cause of this exception, if any */ -class StagehandRetryableException +class BrowserbaseRetryableException @JvmOverloads -constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) +constructor(message: String? = null, cause: Throwable? = null) : + BrowserbaseException(message, cause) diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt similarity index 80% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt index af4ad3b..d88ef6f 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/StagehandServiceException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt @@ -5,9 +5,9 @@ package com.stagehand.api.errors import com.stagehand.api.core.JsonValue import com.stagehand.api.core.http.Headers -abstract class StagehandServiceException +abstract class BrowserbaseServiceException protected constructor(message: String, cause: Throwable? = null) : - StagehandException(message, cause) { + BrowserbaseException(message, cause) { abstract fun statusCode(): Int diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt index e44477e..6682cbf 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt @@ -14,7 +14,7 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : StagehandServiceException("$statusCode: $body", cause) { +) : BrowserbaseServiceException("$statusCode: $body", cause) { override fun statusCode(): Int = statusCode diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt index 55d282f..cf2a3dc 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class NotFoundException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("404: $body", cause) { + BrowserbaseServiceException("404: $body", cause) { override fun statusCode(): Int = 404 diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt index f79f40a..882f883 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class PermissionDeniedException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("403: $body", cause) { + BrowserbaseServiceException("403: $body", cause) { override fun statusCode(): Int = 403 diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt index 1119740..aedc3cf 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class RateLimitException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("429: $body", cause) { + BrowserbaseServiceException("429: $body", cause) { override fun statusCode(): Int = 429 diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt index d3fa413..5eff55d 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class UnauthorizedException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("401: $body", cause) { + BrowserbaseServiceException("401: $body", cause) { override fun statusCode(): Int = 401 diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt index 042ec74..fa6913f 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt @@ -14,7 +14,7 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : StagehandServiceException("$statusCode: $body", cause) { +) : BrowserbaseServiceException("$statusCode: $body", cause) { override fun statusCode(): Int = statusCode diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt similarity index 97% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt index eb3482b..1085120 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class UnprocessableEntityException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("422: $body", cause) { + BrowserbaseServiceException("422: $body", cause) { override fun statusCode(): Int = 422 diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt index 3d159b8..f071b0a 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt @@ -13,7 +13,7 @@ import com.stagehand.api.core.JsonValue import com.stagehand.api.core.checkKnown import com.stagehand.api.core.checkRequired import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -48,7 +48,7 @@ private constructor( /** * Arguments for the method * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun arguments(): List = arguments.getRequired("arguments") @@ -56,7 +56,7 @@ private constructor( /** * Human-readable description of the action * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun description(): String = description.getRequired("description") @@ -64,7 +64,7 @@ private constructor( /** * Method to execute (e.g., "click", "fill") * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun method(): String = method.getRequired("method") @@ -72,7 +72,7 @@ private constructor( /** * CSS or XPath selector for the element * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun selector(): String = selector.getRequired("selector") @@ -80,7 +80,7 @@ private constructor( /** * CDP backend node ID * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") @@ -308,7 +308,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt similarity index 93% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt index 577bfbd..2d21ed5 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt @@ -11,7 +11,7 @@ import com.stagehand.api.core.ExcludeMissing import com.stagehand.api.core.JsonField import com.stagehand.api.core.JsonMissing import com.stagehand.api.core.JsonValue -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -38,7 +38,7 @@ private constructor( /** * API key for the model provider * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun apiKey(): Optional = apiKey.getOptional("apiKey") @@ -46,7 +46,7 @@ private constructor( /** * Custom base URL for API * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun baseUrl(): Optional = baseUrl.getOptional("baseURL") @@ -54,13 +54,13 @@ private constructor( /** * Model name * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun provider(): Optional = provider.getOptional("provider") @@ -219,7 +219,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -303,7 +303,7 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = @@ -311,7 +311,7 @@ private constructor( OPENAI -> Known.OPENAI ANTHROPIC -> Known.ANTHROPIC GOOGLE -> Known.GOOGLE - else -> throw StagehandInvalidDataException("Unknown Provider: $value") + else -> throw BrowserbaseInvalidDataException("Unknown Provider: $value") } /** @@ -320,12 +320,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -343,7 +343,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt similarity index 96% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt index 8631b64..eff4104 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt @@ -27,7 +27,7 @@ import com.stagehand.api.core.getOrThrow import com.stagehand.api.core.http.Headers import com.stagehand.api.core.http.QueryParams import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -53,7 +53,7 @@ private constructor( /** * Natural language instruction * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun input(): Input = body.input() @@ -61,13 +61,13 @@ private constructor( /** * Frame ID to act on (optional) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -372,7 +372,7 @@ private constructor( /** * Natural language instruction * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun input(): Input = input.getRequired("input") @@ -380,13 +380,13 @@ private constructor( /** * Frame ID to act on (optional) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -551,7 +551,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -645,7 +645,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -709,10 +709,10 @@ private constructor( * version than the API, then the API may respond with new variants that the SDK is * unaware of. * - * @throws StagehandInvalidDataException in the default implementation. + * @throws BrowserbaseInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown Input: $json") + throw BrowserbaseInvalidDataException("Unknown Input: $json") } } @@ -782,7 +782,7 @@ private constructor( ) : this(model, timeout, variables, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -790,7 +790,7 @@ private constructor( /** * Timeout in milliseconds * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun timeout(): Optional = timeout.getOptional("timeout") @@ -798,7 +798,7 @@ private constructor( /** * Template variables for instruction * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun variables(): Optional = variables.getOptional("variables") @@ -940,7 +940,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -1030,7 +1030,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -1148,14 +1148,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -1164,12 +1164,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1187,7 +1187,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt index dca978d..f0d6751 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt @@ -13,7 +13,7 @@ import com.stagehand.api.core.JsonValue import com.stagehand.api.core.checkKnown import com.stagehand.api.core.checkRequired import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import kotlin.jvm.optionals.getOrNull @@ -39,7 +39,7 @@ private constructor( /** * Actions that were executed * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun actions(): List = actions.getRequired("actions") @@ -47,7 +47,7 @@ private constructor( /** * Result message * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun message(): String = message.getRequired("message") @@ -55,7 +55,7 @@ private constructor( /** * Whether the action succeeded * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun success(): Boolean = success.getRequired("success") @@ -231,7 +231,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt index 3a162e7..59b3dc9 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt @@ -10,7 +10,7 @@ import com.stagehand.api.core.ExcludeMissing import com.stagehand.api.core.JsonField import com.stagehand.api.core.JsonMissing import com.stagehand.api.core.JsonValue -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -28,7 +28,7 @@ private constructor( ) : this(success, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun success(): Optional = success.getOptional("success") @@ -123,7 +123,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt index 5d77b26..de2624a 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt @@ -26,7 +26,7 @@ import com.stagehand.api.core.checkRequired import com.stagehand.api.core.getOrThrow import com.stagehand.api.core.http.Headers import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -47,19 +47,19 @@ private constructor( fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun agentConfig(): AgentConfig = body.agentConfig() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun executeOptions(): ExecuteOptions = body.executeOptions() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() @@ -368,19 +368,19 @@ private constructor( ) : this(agentConfig, executeOptions, frameId, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun agentConfig(): AgentConfig = agentConfig.getRequired("agentConfig") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun executeOptions(): ExecuteOptions = executeOptions.getRequired("executeOptions") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") @@ -549,7 +549,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -612,25 +612,25 @@ private constructor( /** * Enable Computer Use Agent mode * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun cua(): Optional = cua.getOptional("cua") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun provider(): Optional = provider.getOptional("provider") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") @@ -801,7 +801,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -871,7 +871,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -935,10 +935,10 @@ private constructor( * version than the API, then the API may respond with new variants that the SDK is * unaware of. * - * @throws StagehandInvalidDataException in the default implementation. + * @throws BrowserbaseInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown Model: $json") + throw BrowserbaseInvalidDataException("Unknown Model: $json") } } @@ -1060,15 +1060,15 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and * don't want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a + * known member. */ fun known(): Known = when (this) { OPENAI -> Known.OPENAI ANTHROPIC -> Known.ANTHROPIC GOOGLE -> Known.GOOGLE - else -> throw StagehandInvalidDataException("Unknown Provider: $value") + else -> throw BrowserbaseInvalidDataException("Unknown Provider: $value") } /** @@ -1077,12 +1077,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for * debugging and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have + * @throws BrowserbaseInvalidDataException if this class instance's value does not have * the expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1100,7 +1100,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -1171,7 +1171,7 @@ private constructor( /** * Task for the agent to complete * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun instruction(): String = instruction.getRequired("instruction") @@ -1179,7 +1179,7 @@ private constructor( /** * Visually highlight the cursor during actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun highlightCursor(): Optional = highlightCursor.getOptional("highlightCursor") @@ -1187,7 +1187,7 @@ private constructor( /** * Maximum number of steps the agent can take * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") @@ -1357,7 +1357,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -1462,14 +1462,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -1478,12 +1478,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1501,7 +1501,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt index 6fdda9d..861033b 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt @@ -12,7 +12,7 @@ import com.stagehand.api.core.JsonMissing import com.stagehand.api.core.JsonValue import com.stagehand.api.core.checkKnown import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -35,7 +35,7 @@ private constructor( /** * Final message from the agent * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun message(): Optional = message.getOptional("message") @@ -43,7 +43,7 @@ private constructor( /** * Steps taken by the agent * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun steps(): Optional> = steps.getOptional("steps") @@ -179,7 +179,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt index 7d0c9a4..c6cd822 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt @@ -15,7 +15,7 @@ import com.stagehand.api.core.Params import com.stagehand.api.core.http.Headers import com.stagehand.api.core.http.QueryParams import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -41,7 +41,7 @@ private constructor( /** * Frame ID to extract from * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() @@ -49,13 +49,13 @@ private constructor( /** * Natural language instruction for extraction * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun instruction(): Optional = body.instruction() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -63,7 +63,7 @@ private constructor( /** * JSON Schema for structured output * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun schema(): Optional = body.schema() @@ -374,7 +374,7 @@ private constructor( /** * Frame ID to extract from * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") @@ -382,13 +382,13 @@ private constructor( /** * Natural language instruction for extraction * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun instruction(): Optional = instruction.getOptional("instruction") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -396,7 +396,7 @@ private constructor( /** * JSON Schema for structured output * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun schema(): Optional = schema.getOptional("schema") @@ -562,7 +562,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -621,7 +621,7 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -629,13 +629,13 @@ private constructor( /** * Extract only from elements matching this selector * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun selector(): Optional = selector.getOptional("selector") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun timeout(): Optional = timeout.getOptional("timeout") @@ -774,7 +774,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -883,7 +883,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -979,14 +979,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -995,12 +995,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1018,7 +1018,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt similarity index 96% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt index 3126a4c..912bbcb 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt @@ -22,7 +22,7 @@ import com.stagehand.api.core.JsonValue import com.stagehand.api.core.allMaxBy import com.stagehand.api.core.getOrThrow import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -87,7 +87,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -160,10 +160,10 @@ private constructor( * on an older version than the API, then the API may respond with new variants that the SDK * is unaware of. * - * @throws StagehandInvalidDataException in the default implementation. + * @throws BrowserbaseInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown SessionExtractResponse: $json") + throw BrowserbaseInvalidDataException("Unknown SessionExtractResponse: $json") } } @@ -230,7 +230,7 @@ private constructor( ) : this(extraction, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun extraction(): Optional = extraction.getOptional("extraction") @@ -327,7 +327,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -428,7 +428,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt index 634a032..bb111b3 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt @@ -15,7 +15,7 @@ import com.stagehand.api.core.Params import com.stagehand.api.core.checkRequired import com.stagehand.api.core.http.Headers import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -38,19 +38,19 @@ private constructor( /** * URL to navigate to * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun url(): String = body.url() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -348,19 +348,19 @@ private constructor( /** * URL to navigate to * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun url(): String = url.getRequired("url") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -518,7 +518,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -573,7 +573,7 @@ private constructor( /** * When to consider navigation complete * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun waitUntil(): Optional = waitUntil.getOptional("waitUntil") @@ -671,7 +671,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -757,15 +757,15 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and * don't want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a + * known member. */ fun known(): Known = when (this) { LOAD -> Known.LOAD DOMCONTENTLOADED -> Known.DOMCONTENTLOADED NETWORKIDLE -> Known.NETWORKIDLE - else -> throw StagehandInvalidDataException("Unknown WaitUntil: $value") + else -> throw BrowserbaseInvalidDataException("Unknown WaitUntil: $value") } /** @@ -774,12 +774,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for * debugging and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have + * @throws BrowserbaseInvalidDataException if this class instance's value does not have * the expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -797,7 +797,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -907,14 +907,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -923,12 +923,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -946,7 +946,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt similarity index 94% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt index b6a5d86..e570e58 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt @@ -10,7 +10,7 @@ import com.stagehand.api.core.ExcludeMissing import com.stagehand.api.core.JsonField import com.stagehand.api.core.JsonMissing import com.stagehand.api.core.JsonValue -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -33,19 +33,19 @@ private constructor( ) : this(ok, status, url, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun ok(): Optional = ok.getOptional("ok") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun status(): Optional = status.getOptional("status") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun url(): Optional = url.getOptional("url") @@ -180,7 +180,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt index e3d18de..84d197c 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt @@ -14,7 +14,7 @@ import com.stagehand.api.core.JsonValue import com.stagehand.api.core.Params import com.stagehand.api.core.http.Headers import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -40,7 +40,7 @@ private constructor( /** * Frame ID to observe * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() @@ -48,13 +48,13 @@ private constructor( /** * Natural language instruction to filter actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun instruction(): Optional = body.instruction() /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -344,7 +344,7 @@ private constructor( /** * Frame ID to observe * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") @@ -352,13 +352,13 @@ private constructor( /** * Natural language instruction to filter actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun instruction(): Optional = instruction.getOptional("instruction") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -502,7 +502,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -559,7 +559,7 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -567,13 +567,13 @@ private constructor( /** * Observe only elements matching this selector * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun selector(): Optional = selector.getOptional("selector") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun timeout(): Optional = timeout.getOptional("timeout") @@ -712,7 +712,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -817,14 +817,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -833,12 +833,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -856,7 +856,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt similarity index 94% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt index 4b7050c..0a52ee0 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt @@ -15,7 +15,7 @@ import com.stagehand.api.core.Params import com.stagehand.api.core.checkRequired import com.stagehand.api.core.http.Headers import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional @@ -35,7 +35,7 @@ private constructor( /** * Environment to run the browser in * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun env(): Env = body.env() @@ -43,7 +43,7 @@ private constructor( /** * API key for Browserbase (required when env=BROWSERBASE) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun apiKey(): Optional = body.apiKey() @@ -51,7 +51,7 @@ private constructor( /** * Timeout in ms to wait for DOM to settle * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun domSettleTimeout(): Optional = body.domSettleTimeout() @@ -59,7 +59,7 @@ private constructor( /** * Options for local browser launch * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun localBrowserLaunchOptions(): Optional = @@ -68,7 +68,7 @@ private constructor( /** * AI model to use for actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun model(): Optional = body.model() @@ -76,7 +76,7 @@ private constructor( /** * Project ID for Browserbase (required when env=BROWSERBASE) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun projectId(): Optional = body.projectId() @@ -84,7 +84,7 @@ private constructor( /** * Enable self-healing for failed actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun selfHeal(): Optional = body.selfHeal() @@ -92,7 +92,7 @@ private constructor( /** * Custom system prompt for AI actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun systemPrompt(): Optional = body.systemPrompt() @@ -100,7 +100,7 @@ private constructor( /** * Logging verbosity level * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun verbose(): Optional = body.verbose() @@ -532,7 +532,7 @@ private constructor( /** * Environment to run the browser in * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun env(): Env = env.getRequired("env") @@ -540,7 +540,7 @@ private constructor( /** * API key for Browserbase (required when env=BROWSERBASE) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun apiKey(): Optional = apiKey.getOptional("apiKey") @@ -548,7 +548,7 @@ private constructor( /** * Timeout in ms to wait for DOM to settle * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun domSettleTimeout(): Optional = domSettleTimeout.getOptional("domSettleTimeout") @@ -556,7 +556,7 @@ private constructor( /** * Options for local browser launch * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun localBrowserLaunchOptions(): Optional = @@ -565,7 +565,7 @@ private constructor( /** * AI model to use for actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -573,7 +573,7 @@ private constructor( /** * Project ID for Browserbase (required when env=BROWSERBASE) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun projectId(): Optional = projectId.getOptional("projectId") @@ -581,7 +581,7 @@ private constructor( /** * Enable self-healing for failed actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun selfHeal(): Optional = selfHeal.getOptional("selfHeal") @@ -589,7 +589,7 @@ private constructor( /** * Custom system prompt for AI actions * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") @@ -597,7 +597,7 @@ private constructor( /** * Logging verbosity level * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun verbose(): Optional = verbose.getOptional("verbose") @@ -914,7 +914,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -1039,14 +1039,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known + * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { LOCAL -> Known.LOCAL BROWSERBASE -> Known.BROWSERBASE - else -> throw StagehandInvalidDataException("Unknown Env: $value") + else -> throw BrowserbaseInvalidDataException("Unknown Env: $value") } /** @@ -1055,12 +1055,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws StagehandInvalidDataException if this class instance's value does not have the + * @throws BrowserbaseInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + BrowserbaseInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1078,7 +1078,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } @@ -1119,7 +1119,7 @@ private constructor( ) : this(headless, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun headless(): Optional = headless.getOptional("headless") @@ -1218,7 +1218,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt similarity index 95% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt index b8bc8da..e78188e 100644 --- a/stagehand-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt @@ -11,7 +11,7 @@ import com.stagehand.api.core.JsonField import com.stagehand.api.core.JsonMissing import com.stagehand.api.core.JsonValue import com.stagehand.api.core.checkRequired -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects @@ -32,7 +32,7 @@ private constructor( /** * Whether the session is ready to use * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun available(): Boolean = available.getRequired("available") @@ -40,7 +40,7 @@ private constructor( /** * Unique identifier for the session * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun sessionId(): String = sessionId.getRequired("sessionId") @@ -179,7 +179,7 @@ private constructor( try { validate() true - } catch (e: StagehandInvalidDataException) { + } catch (e: BrowserbaseInvalidDataException) { false } diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt diff --git a/stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt b/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt similarity index 100% rename from stagehand-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt rename to browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt diff --git a/stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro b/browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro similarity index 100% rename from stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro rename to browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt similarity index 98% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt index 380321a..46bbd9f 100644 --- a/stagehand-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt @@ -7,7 +7,7 @@ import com.github.tomakehurst.wiremock.stubbing.Scenario import com.stagehand.api.client.okhttp.OkHttpClient import com.stagehand.api.core.RequestOptions import com.stagehand.api.core.Sleeper -import com.stagehand.api.errors.StagehandRetryableException +import com.stagehand.api.errors.BrowserbaseRetryableException import java.io.InputStream import java.time.Duration import java.util.concurrent.CompletableFuture @@ -267,7 +267,7 @@ internal class RetryingHttpClientTest { ): HttpResponse { callCount++ if (callCount == 1) { - throw StagehandRetryableException("Simulated retryable failure") + throw BrowserbaseRetryableException("Simulated retryable failure") } return httpClient.execute(request, requestOptions) } @@ -280,7 +280,7 @@ internal class RetryingHttpClientTest { if (callCount == 1) { val future = CompletableFuture() future.completeExceptionally( - StagehandRetryableException("Simulated retryable failure") + BrowserbaseRetryableException("Simulated retryable failure") ) return future } diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt similarity index 95% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt index 22f62ea..9615580 100644 --- a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt @@ -5,7 +5,7 @@ package com.stagehand.api.models.sessions import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.stagehand.api.core.JsonValue import com.stagehand.api.core.jsonMapper -import com.stagehand.api.errors.StagehandInvalidDataException +import com.stagehand.api.errors.BrowserbaseInvalidDataException import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @@ -88,7 +88,7 @@ internal class SessionExtractResponseTest { val sessionExtractResponse = jsonMapper().convertValue(testCase.value, jacksonTypeRef()) - val e = assertThrows { sessionExtractResponse.validate() } + val e = assertThrows { sessionExtractResponse.validate() } assertThat(e).hasMessageStartingWith("Unknown ") } } diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt similarity index 100% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt similarity index 98% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt index f35e2ad..8fc0701 100644 --- a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt @@ -8,17 +8,17 @@ import com.github.tomakehurst.wiremock.client.WireMock.status import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import com.stagehand.api.client.StagehandClient -import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.client.BrowserbaseClient +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient import com.stagehand.api.core.JsonValue import com.stagehand.api.core.http.Headers import com.stagehand.api.core.jsonMapper import com.stagehand.api.errors.BadRequestException +import com.stagehand.api.errors.BrowserbaseException import com.stagehand.api.errors.InternalServerException import com.stagehand.api.errors.NotFoundException import com.stagehand.api.errors.PermissionDeniedException import com.stagehand.api.errors.RateLimitException -import com.stagehand.api.errors.StagehandException import com.stagehand.api.errors.UnauthorizedException import com.stagehand.api.errors.UnexpectedStatusCodeException import com.stagehand.api.errors.UnprocessableEntityException @@ -47,12 +47,12 @@ internal class ErrorHandlingTest { private const val NOT_JSON: String = "Not JSON" } - private lateinit var client: StagehandClient + private lateinit var client: BrowserbaseClient @BeforeEach fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(wmRuntimeInfo.httpBaseUrl) .apiKey("My API Key") .build() @@ -643,7 +643,7 @@ internal class ErrorHandlingTest { ) val e = - assertThrows { + assertThrows { sessionService.start( SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt similarity index 92% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt index 801d8ff..76f9dd5 100644 --- a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt @@ -12,8 +12,8 @@ import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.client.WireMock.verify import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import com.stagehand.api.client.StagehandClient -import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.client.BrowserbaseClient +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient import com.stagehand.api.core.JsonValue import com.stagehand.api.models.sessions.SessionStartParams import org.junit.jupiter.api.BeforeEach @@ -25,12 +25,12 @@ import org.junit.jupiter.api.parallel.ResourceLock @ResourceLock("https://github.com/wiremock/wiremock/issues/169") internal class ServiceParamsTest { - private lateinit var client: StagehandClient + private lateinit var client: BrowserbaseClient @BeforeEach fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(wmRuntimeInfo.httpBaseUrl) .apiKey("My API Key") .build() diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt similarity index 95% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt index 49b568d..e01497b 100644 --- a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt @@ -3,7 +3,7 @@ package com.stagehand.api.services.async import com.stagehand.api.TestServerExtension -import com.stagehand.api.client.okhttp.StagehandOkHttpClientAsync +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClientAsync import com.stagehand.api.core.JsonValue import com.stagehand.api.models.sessions.ModelConfig import com.stagehand.api.models.sessions.SessionActParams @@ -24,7 +24,7 @@ internal class SessionServiceAsyncTest { @Test fun act() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -66,7 +66,7 @@ internal class SessionServiceAsyncTest { @Test fun end() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -82,7 +82,7 @@ internal class SessionServiceAsyncTest { @Test fun executeAgent() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -120,7 +120,7 @@ internal class SessionServiceAsyncTest { @Test fun extract() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -163,7 +163,7 @@ internal class SessionServiceAsyncTest { @Test fun navigate() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -193,7 +193,7 @@ internal class SessionServiceAsyncTest { @Test fun observe() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -231,7 +231,7 @@ internal class SessionServiceAsyncTest { @Test fun start() { val client = - StagehandOkHttpClientAsync.builder() + BrowserbaseOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() diff --git a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt similarity index 95% rename from stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt rename to browserbase-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt index 8b92fe7..e0d7f43 100644 --- a/stagehand-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt @@ -3,7 +3,7 @@ package com.stagehand.api.services.blocking import com.stagehand.api.TestServerExtension -import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient import com.stagehand.api.core.JsonValue import com.stagehand.api.models.sessions.ModelConfig import com.stagehand.api.models.sessions.SessionActParams @@ -24,7 +24,7 @@ internal class SessionServiceTest { @Test fun act() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -65,7 +65,7 @@ internal class SessionServiceTest { @Test fun end() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -80,7 +80,7 @@ internal class SessionServiceTest { @Test fun executeAgent() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -117,7 +117,7 @@ internal class SessionServiceTest { @Test fun extract() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -159,7 +159,7 @@ internal class SessionServiceTest { @Test fun navigate() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -188,7 +188,7 @@ internal class SessionServiceTest { @Test fun observe() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -225,7 +225,7 @@ internal class SessionServiceTest { @Test fun start() { val client = - StagehandOkHttpClient.builder() + BrowserbaseOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() diff --git a/browserbase-java-example/build.gradle.kts b/browserbase-java-example/build.gradle.kts new file mode 100644 index 0000000..61df3c5 --- /dev/null +++ b/browserbase-java-example/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + id("browserbase.java") + application +} + +repositories { + mavenCentral() +} + +dependencies { + implementation(project(":browserbase-java")) +} + +tasks.withType().configureEach { + // Allow using more modern APIs, like `List.of` and `Map.of`, in examples. + options.release.set(9) +} + +application { + // Use `./gradlew :browserbase-java-example:run` to run `Main` + // Use `./gradlew :browserbase-java-example:run -Pexample=Something` to run `SomethingExample` + mainClass = "com.stagehand.api.example.${ + if (project.hasProperty("example")) + "${project.property("example")}Example" + else + "Main" + }" +} diff --git a/browserbase-java-lib/.keep b/browserbase-java-lib/.keep new file mode 100644 index 0000000..5e2c99f --- /dev/null +++ b/browserbase-java-lib/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store custom files to expand the SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/stagehand-java-proguard-test/build.gradle.kts b/browserbase-java-proguard-test/build.gradle.kts similarity index 90% rename from stagehand-java-proguard-test/build.gradle.kts rename to browserbase-java-proguard-test/build.gradle.kts index a4cde75..4d0189d 100644 --- a/stagehand-java-proguard-test/build.gradle.kts +++ b/browserbase-java-proguard-test/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("stagehand.kotlin") + id("browserbase.kotlin") id("com.gradleup.shadow") version "8.3.8" } @@ -15,7 +15,7 @@ buildscript { } dependencies { - testImplementation(project(":stagehand-java")) + testImplementation(project(":browserbase-java")) testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") @@ -51,7 +51,7 @@ val proguardJar by tasks.registering(proguard.gradle.ProGuardTask::class) { } configuration("./test.pro") - configuration("../stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro") + configuration("../browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro") } val testProGuard by tasks.registering(JavaExec::class) { @@ -78,7 +78,7 @@ val r8Jar by tasks.registering(JavaExec::class) { "--output", r8JarPath, "--lib", System.getProperty("java.home"), "--pg-conf", "./test.pro", - "--pg-conf", "../stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro", + "--pg-conf", "../browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro", "--pg-map-output", "${layout.buildDirectory.get()}/r8-mapping.txt", tasks.shadowJar.get().archiveFile.get().asFile.absolutePath, ) diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt b/browserbase-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt similarity index 93% rename from stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt rename to browserbase-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt index 13ad08e..82fd595 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt +++ b/browserbase-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt @@ -3,7 +3,7 @@ package com.stagehand.api.proguard import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.client.okhttp.StagehandOkHttpClient +import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient import com.stagehand.api.core.jsonMapper import com.stagehand.api.models.sessions.Action import com.stagehand.api.models.sessions.SessionExtractResponse @@ -38,14 +38,14 @@ internal class ProGuardCompatibilityTest { @Test fun proguardRules() { val rulesFile = - javaClass.classLoader.getResourceAsStream("META-INF/proguard/stagehand-java-core.pro") + javaClass.classLoader.getResourceAsStream("META-INF/proguard/browserbase-java-core.pro") assertThat(rulesFile).isNotNull() } @Test fun client() { - val client = StagehandOkHttpClient.builder().apiKey("My API Key").build() + val client = BrowserbaseOkHttpClient.builder().apiKey("My API Key").build() assertThat(client).isNotNull() assertThat(client.sessions()).isNotNull() diff --git a/stagehand-java-proguard-test/test.pro b/browserbase-java-proguard-test/test.pro similarity index 100% rename from stagehand-java-proguard-test/test.pro rename to browserbase-java-proguard-test/test.pro diff --git a/stagehand-java/build.gradle.kts b/browserbase-java/build.gradle.kts similarity index 85% rename from stagehand-java/build.gradle.kts rename to browserbase-java/build.gradle.kts index 6d32486..86b7f8c 100644 --- a/stagehand-java/build.gradle.kts +++ b/browserbase-java/build.gradle.kts @@ -1,10 +1,10 @@ plugins { - id("stagehand.kotlin") - id("stagehand.publish") + id("browserbase.kotlin") + id("browserbase.publish") } dependencies { - api(project(":stagehand-java-client-okhttp")) + api(project(":browserbase-java-client-okhttp")) } // Redefine `dokkaJavadoc` to: diff --git a/build.gradle.kts b/build.gradle.kts index 5703c44..2fffcae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,7 +32,7 @@ subprojects { // Avoid race conditions between `dokkaJavadocCollector` and `dokkaJavadocJar` tasks tasks.named("dokkaJavadocCollector").configure { subprojects.flatMap { it.tasks } - .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } + .filter { it.project.name != "browserbase-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/browserbase.java.gradle.kts similarity index 100% rename from buildSrc/src/main/kotlin/stagehand.java.gradle.kts rename to buildSrc/src/main/kotlin/browserbase.java.gradle.kts diff --git a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts b/buildSrc/src/main/kotlin/browserbase.kotlin.gradle.kts similarity index 99% rename from buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts rename to buildSrc/src/main/kotlin/browserbase.kotlin.gradle.kts index f3f48d1..08574e8 100644 --- a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/browserbase.kotlin.gradle.kts @@ -2,7 +2,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { - id("stagehand.java") + id("browserbase.java") kotlin("jvm") } diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/browserbase.publish.gradle.kts similarity index 97% rename from buildSrc/src/main/kotlin/stagehand.publish.gradle.kts rename to buildSrc/src/main/kotlin/browserbase.publish.gradle.kts index 326eeea..6822ae8 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/browserbase.publish.gradle.kts @@ -21,7 +21,7 @@ configure { developers { developer { - name.set("Stagehand") + name.set("Browserbase") } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 02623dd..53191ab 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,11 +1,11 @@ -rootProject.name = "stagehand-java-root" +rootProject.name = "browserbase-java-root" val projectNames = rootDir.listFiles() ?.asSequence() .orEmpty() .filter { file -> file.isDirectory && - file.name.startsWith("stagehand-java") && + file.name.startsWith("browserbase-java") && file.listFiles()?.asSequence().orEmpty().any { it.name == "build.gradle.kts" } } .map { it.name } From 0132f3264221c8bc4e7148e9573dde7f21438973 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:13:53 +0000 Subject: [PATCH 011/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 164 +++++++++--------- .../client/okhttp/BrowserbaseOkHttpClient.kt | 24 +-- .../okhttp/BrowserbaseOkHttpClientAsync.kt | 24 +-- .../api/client/okhttp/OkHttpClient.kt | 22 +-- .../api/client/okhttp/OkHttpClientTest.kt | 6 +- .../api/client/BrowserbaseClient.kt | 6 +- .../api/client/BrowserbaseClientAsync.kt | 6 +- .../api/client/BrowserbaseClientAsyncImpl.kt | 10 +- .../api/client/BrowserbaseClientImpl.kt | 10 +- .../api/core/BaseDeserializer.kt | 2 +- .../api/core/BaseSerializer.kt | 2 +- .../api/core/Check.kt | 2 +- .../api/core/ClientOptions.kt | 18 +- .../api/core/DefaultSleeper.kt | 2 +- .../api/core/ObjectMappers.kt | 2 +- .../api/core/Params.kt | 6 +- .../api/core/PhantomReachable.kt | 4 +- .../core/PhantomReachableExecutorService.kt | 2 +- .../api/core/PhantomReachableSleeper.kt | 2 +- .../api/core/PrepareRequest.kt | 4 +- .../api/core/Properties.kt | 4 +- .../api/core/RequestOptions.kt | 2 +- .../api/core/Sleeper.kt | 2 +- .../api/core/Timeout.kt | 2 +- .../api/core/Utils.kt | 4 +- .../api/core/Values.kt | 4 +- .../api/core/handlers/ErrorHandler.kt | 26 +-- .../api/core/handlers/JsonHandler.kt | 8 +- .../api/core/handlers/StringHandler.kt | 6 +- .../api/core/http/AsyncStreamResponse.kt | 4 +- .../api/core/http/Headers.kt | 22 +-- .../api/core/http/HttpClient.kt | 4 +- .../api/core/http/HttpMethod.kt | 2 +- .../api/core/http/HttpRequest.kt | 6 +- .../api/core/http/HttpRequestBodies.kt | 6 +- .../api/core/http/HttpRequestBody.kt | 2 +- .../api/core/http/HttpResponse.kt | 2 +- .../api/core/http/HttpResponseFor.kt | 2 +- ...ntomReachableClosingAsyncStreamResponse.kt | 6 +- .../http/PhantomReachableClosingHttpClient.kt | 6 +- .../PhantomReachableClosingStreamResponse.kt | 4 +- .../api/core/http/QueryParams.kt | 22 +-- .../api/core/http/RetryingHttpClient.kt | 16 +- .../api/core/http/StreamResponse.kt | 2 +- .../api/errors/BadRequestException.kt | 8 +- .../api/errors/BrowserbaseException.kt | 2 +- .../errors/BrowserbaseInvalidDataException.kt | 2 +- .../api/errors/BrowserbaseIoException.kt | 2 +- .../errors/BrowserbaseRetryableException.kt | 2 +- .../api/errors/BrowserbaseServiceException.kt | 6 +- .../api/errors/InternalServerException.kt | 8 +- .../api/errors/NotFoundException.kt | 8 +- .../api/errors/PermissionDeniedException.kt | 8 +- .../api/errors/RateLimitException.kt | 8 +- .../api/errors/UnauthorizedException.kt | 8 +- .../errors/UnexpectedStatusCodeException.kt | 8 +- .../errors/UnprocessableEntityException.kt | 8 +- .../api/models/sessions/Action.kt | 20 +-- .../api/models/sessions/ModelConfig.kt | 16 +- .../api/models/sessions/SessionActParams.kt | 34 ++-- .../api/models/sessions/SessionActResponse.kt | 20 +-- .../api/models/sessions/SessionEndParams.kt | 12 +- .../api/models/sessions/SessionEndResponse.kt | 12 +- .../sessions/SessionExecuteAgentParams.kt | 32 ++-- .../sessions/SessionExecuteAgentResponse.kt | 18 +- .../models/sessions/SessionExtractParams.kt | 24 +-- .../models/sessions/SessionExtractResponse.kt | 24 +-- .../models/sessions/SessionNavigateParams.kt | 24 +-- .../sessions/SessionNavigateResponse.kt | 12 +- .../models/sessions/SessionObserveParams.kt | 22 +-- .../api/models/sessions/SessionStartParams.kt | 24 +-- .../models/sessions/SessionStartResponse.kt | 16 +- .../api/services/async/SessionServiceAsync.kt | 38 ++-- .../services/async/SessionServiceAsyncImpl.kt | 58 +++---- .../api/services/blocking/SessionService.kt | 38 ++-- .../services/blocking/SessionServiceImpl.kt | 58 +++---- .../proguard/browserbase-java-core.pro | 6 +- .../api/TestServerExtension.kt | 2 +- .../api/core/ClientOptionsTest.kt | 4 +- .../api/core/ObjectMappersTest.kt | 2 +- .../api/core/PhantomReachableTest.kt | 2 +- .../api/core/UtilsTest.kt | 2 +- .../api/core/ValuesTest.kt | 2 +- .../api/core/http/AsyncStreamResponseTest.kt | 2 +- .../api/core/http/HeadersTest.kt | 2 +- .../api/core/http/QueryParamsTest.kt | 2 +- .../api/core/http/RetryingHttpClientTest.kt | 10 +- .../api/models/sessions/ActionTest.kt | 4 +- .../api/models/sessions/ModelConfigTest.kt | 4 +- .../models/sessions/SessionActParamsTest.kt | 6 +- .../models/sessions/SessionActResponseTest.kt | 4 +- .../models/sessions/SessionEndParamsTest.kt | 2 +- .../models/sessions/SessionEndResponseTest.kt | 4 +- .../sessions/SessionExecuteAgentParamsTest.kt | 4 +- .../SessionExecuteAgentResponseTest.kt | 6 +- .../sessions/SessionExtractParamsTest.kt | 6 +- .../sessions/SessionExtractResponseTest.kt | 8 +- .../sessions/SessionNavigateParamsTest.kt | 4 +- .../sessions/SessionNavigateResponseTest.kt | 4 +- .../sessions/SessionObserveParamsTest.kt | 4 +- .../models/sessions/SessionStartParamsTest.kt | 2 +- .../sessions/SessionStartResponseTest.kt | 4 +- .../api/services/ErrorHandlingTest.kt | 34 ++-- .../api/services/ServiceParamsTest.kt | 10 +- .../services/async/SessionServiceAsyncTest.kt | 22 +-- .../services/blocking/SessionServiceTest.kt | 24 +-- .../build.gradle.kts | 4 +- .../api/proguard/ProGuardCompatibilityTest.kt | 10 +- browserbase-java-proguard-test/test.pro | 2 +- build.gradle.kts | 2 +- 111 files changed, 637 insertions(+), 637 deletions(-) rename browserbase-java-client-okhttp/src/main/kotlin/com/{stagehand => browserbase}/api/client/okhttp/BrowserbaseOkHttpClient.kt (95%) rename browserbase-java-client-okhttp/src/main/kotlin/com/{stagehand => browserbase}/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt (95%) rename browserbase-java-client-okhttp/src/main/kotlin/com/{stagehand => browserbase}/api/client/okhttp/OkHttpClient.kt (94%) rename browserbase-java-client-okhttp/src/test/kotlin/com/{stagehand => browserbase}/api/client/okhttp/OkHttpClientTest.kt (90%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/client/BrowserbaseClient.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/client/BrowserbaseClientAsync.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/client/BrowserbaseClientAsyncImpl.kt (88%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/client/BrowserbaseClientImpl.kt (88%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/BaseDeserializer.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/BaseSerializer.kt (84%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Check.kt (99%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/ClientOptions.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/DefaultSleeper.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/ObjectMappers.kt (99%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Params.kt (75%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/PhantomReachable.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/PhantomReachableExecutorService.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/PhantomReachableSleeper.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/PrepareRequest.kt (90%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Properties.kt (92%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/RequestOptions.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Sleeper.kt (94%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Timeout.kt (99%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Utils.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/Values.kt (99%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/handlers/ErrorHandler.kt (80%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/handlers/JsonHandler.kt (71%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/handlers/StringHandler.kt (66%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/AsyncStreamResponse.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/Headers.kt (87%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpClient.kt (89%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpMethod.kt (76%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpRequest.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpRequestBodies.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpRequestBody.kt (94%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpResponse.kt (91%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/HttpResponseFor.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt (91%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/PhantomReachableClosingHttpClient.kt (84%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/PhantomReachableClosingStreamResponse.kt (85%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/QueryParams.kt (90%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/RetryingHttpClient.kt (96%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/core/http/StreamResponse.kt (92%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/BadRequestException.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/BrowserbaseException.kt (80%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/BrowserbaseInvalidDataException.kt (81%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/BrowserbaseIoException.kt (81%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/BrowserbaseRetryableException.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/BrowserbaseServiceException.kt (72%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/InternalServerException.kt (94%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/NotFoundException.kt (92%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/PermissionDeniedException.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/RateLimitException.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/UnauthorizedException.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/UnexpectedStatusCodeException.kt (94%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/errors/UnprocessableEntityException.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/Action.kt (96%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/ModelConfig.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionActParams.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionActResponse.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionEndParams.kt (97%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionEndResponse.kt (94%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExecuteAgentParams.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExecuteAgentResponse.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExtractParams.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExtractResponse.kt (96%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionNavigateParams.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionNavigateResponse.kt (96%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionObserveParams.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionStartParams.kt (98%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionStartResponse.kt (95%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/services/async/SessionServiceAsync.kt (94%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/services/async/SessionServiceAsyncImpl.kt (89%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/services/blocking/SessionService.kt (93%) rename browserbase-java-core/src/main/kotlin/com/{stagehand => browserbase}/api/services/blocking/SessionServiceImpl.kt (88%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/TestServerExtension.kt (98%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/ClientOptionsTest.kt (93%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/ObjectMappersTest.kt (99%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/PhantomReachableTest.kt (95%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/UtilsTest.kt (97%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/ValuesTest.kt (99%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/http/AsyncStreamResponseTest.kt (99%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/http/HeadersTest.kt (99%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/http/QueryParamsTest.kt (99%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/core/http/RetryingHttpClientTest.kt (98%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/ActionTest.kt (94%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/ModelConfigTest.kt (94%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionActParamsTest.kt (97%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionActResponseTest.kt (96%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionEndParamsTest.kt (93%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionEndResponseTest.kt (91%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExecuteAgentParamsTest.kt (98%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExecuteAgentResponseTest.kt (91%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExtractParamsTest.kt (97%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionExtractResponseTest.kt (94%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionNavigateParamsTest.kt (97%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionNavigateResponseTest.kt (92%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionObserveParamsTest.kt (98%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionStartParamsTest.kt (98%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/models/sessions/SessionStartResponseTest.kt (93%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/services/ErrorHandlingTest.kt (96%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/services/ServiceParamsTest.kt (90%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/services/async/SessionServiceAsyncTest.kt (93%) rename browserbase-java-core/src/test/kotlin/com/{stagehand => browserbase}/api/services/blocking/SessionServiceTest.kt (93%) rename browserbase-java-proguard-test/src/test/kotlin/com/{stagehand => browserbase}/api/proguard/ProGuardCompatibilityTest.kt (91%) diff --git a/.stats.yml b/.stats.yml index 18b7af8..ae2d02d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 1548ab91b7e8621f7fa79e8cff0c3f93 +config_hash: 905fc70fd4344c8631aab6754bffd883 diff --git a/README.md b/README.md index 9c68b67..390f269 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.stagehand.api/browserbase-java)](https://central.sonatype.com/artifact/com.stagehand.api/browserbase-java/0.0.1) -[![javadoc](https://javadoc.io/badge2/com.stagehand.api/browserbase-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.stagehand.api/browserbase-java/0.0.1) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/browserbase-java)](https://central.sonatype.com/artifact/com.browserbase.api/browserbase-java/0.0.1) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/browserbase-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/browserbase-java/0.0.1) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.stagehand.api/browserbase-java/0.0.1). +The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/browserbase-java/0.0.1). @@ -24,14 +24,14 @@ The REST API documentation can be found on [browserbase.com](https://browserbase ### Gradle ```kotlin -implementation("com.stagehand.api:browserbase-java:0.0.1") +implementation("com.browserbase.api:browserbase-java:0.0.1") ``` ### Maven ```xml - com.stagehand.api + com.browserbase.api browserbase-java 0.0.1 @@ -46,10 +46,10 @@ This library requires Java 8 or later. ## Usage ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -import com.stagehand.api.models.sessions.SessionStartParams; -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties // Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables @@ -66,8 +66,8 @@ SessionStartResponse response = client.sessions().start(params); Configure the client using system properties or environment variables: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties // Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables @@ -77,8 +77,8 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); Or manually: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .apiKey("My API Key") @@ -88,8 +88,8 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() Or using a combination of the two approaches: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties @@ -117,7 +117,7 @@ System properties take precedence over environment variables. To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service: ```java -import com.stagehand.api.client.BrowserbaseClient; +import com.browserbase.api.client.BrowserbaseClient; BrowserbaseClient clientWithOptions = client.withOptions(optionsBuilder -> { optionsBuilder.baseUrl("https://example.com"); @@ -146,10 +146,10 @@ Because each class is immutable, builder modification will _never_ affect alread The default client is synchronous. To switch to asynchronous execution, call the `async()` method: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; -import com.stagehand.api.models.sessions.SessionStartParams; -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties @@ -165,10 +165,10 @@ CompletableFuture response = client.async().sessions().sta Or create an asynchronous client from the beginning: ```java -import com.stagehand.api.client.BrowserbaseClientAsync; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClientAsync; -import com.stagehand.api.models.sessions.SessionStartParams; -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.client.BrowserbaseClientAsync; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClientAsync; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties @@ -190,10 +190,10 @@ The SDK defines methods that deserialize responses into instances of Java classe To access this data, prefix any HTTP method call on a client or service with `withRawResponse()`: ```java -import com.stagehand.api.core.http.Headers; -import com.stagehand.api.core.http.HttpResponseFor; -import com.stagehand.api.models.sessions.SessionStartParams; -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.core.http.Headers; +import com.browserbase.api.core.http.HttpResponseFor; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -207,7 +207,7 @@ Headers headers = response.headers(); You can still deserialize the response into an instance of a Java class if needed: ```java -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartResponse parsedResponse = response.parse(); ``` @@ -216,26 +216,26 @@ SessionStartResponse parsedResponse = response.parse(); The SDK throws custom unchecked exception types: -- [`BrowserbaseServiceException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: +- [`BrowserbaseServiceException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: - | Status | Exception | - | ------ | ---------------------------------------------------------------------------------------------------------------------------------- | - | 400 | [`BadRequestException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt) | - | 401 | [`UnauthorizedException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt) | - | 403 | [`PermissionDeniedException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt) | - | 404 | [`NotFoundException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt) | - | 422 | [`UnprocessableEntityException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt) | - | 429 | [`RateLimitException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt) | - | 5xx | [`InternalServerException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt) | - | others | [`UnexpectedStatusCodeException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt) | + | Status | Exception | + | ------ | ------------------------------------------------------------------------------------------------------------------------------------ | + | 400 | [`BadRequestException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt) | + | 401 | [`UnauthorizedException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt) | + | 403 | [`PermissionDeniedException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt) | + | 404 | [`NotFoundException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt) | + | 422 | [`UnprocessableEntityException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt) | + | 429 | [`RateLimitException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt) | + | 5xx | [`InternalServerException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt) | + | others | [`UnexpectedStatusCodeException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt) | -- [`BrowserbaseIoException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt): I/O networking errors. +- [`BrowserbaseIoException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt): I/O networking errors. -- [`BrowserbaseRetryableException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt): Generic error indicating a failure that could be retried by the client. +- [`BrowserbaseRetryableException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt): Generic error indicating a failure that could be retried by the client. -- [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. +- [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. -- [`BrowserbaseException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. +- [`BrowserbaseException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. ## Logging @@ -265,7 +265,7 @@ The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON seri The SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config). -If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt). +If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt). > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. @@ -289,8 +289,8 @@ The API may also explicitly instruct the SDK to retry or not retry a request. To set a custom number of retries, configure the client using the `maxRetries` method: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() @@ -305,7 +305,7 @@ Requests time out after 1 minute by default. To set a custom timeout, configure the method call using the `timeout` method: ```java -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartResponse response = client.sessions().start( params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() @@ -315,8 +315,8 @@ SessionStartResponse response = client.sessions().start( Or configure the default for all method calls at the client level: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; import java.time.Duration; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() @@ -330,8 +330,8 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() To route requests through a proxy, configure the client using the `proxy` method: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; import java.net.InetSocketAddress; import java.net.Proxy; @@ -354,8 +354,8 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() @@ -371,8 +371,8 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() The SDK sends requests to the production by default. To send requests to a different environment, configure the client like so: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() @@ -388,10 +388,10 @@ The SDK consists of three artifacts: - `browserbase-java-core` - Contains core SDK logic - Does not depend on [OkHttp](https://square.github.io/okhttp) - - Exposes [`BrowserbaseClient`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt), [`BrowserbaseClientAsync`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt), [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt), and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), all of which can work with any HTTP client + - Exposes [`BrowserbaseClient`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt), [`BrowserbaseClientAsync`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt), [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt), and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), all of which can work with any HTTP client - `browserbase-java-client-okhttp` - Depends on [OkHttp](https://square.github.io/okhttp) - - Exposes [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) and [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), which provide a way to construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt) and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), respectively, using OkHttp + - Exposes [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) and [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), which provide a way to construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt) and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), respectively, using OkHttp - `browserbase-java` - Depends on and exposes the APIs of both `browserbase-java-core` and `browserbase-java-client-okhttp` - Does not have its own logic @@ -406,16 +406,16 @@ This structure allows replacing the SDK's default HTTP client without pulling in To use a customized `OkHttpClient`: 1. Replace your [`browserbase-java` dependency](#installation) with `browserbase-java-core` -2. Copy `browserbase-java-client-okhttp`'s [`OkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt) class into your code and customize it -3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your customized client +2. Copy `browserbase-java-client-okhttp`'s [`OkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt) class into your code and customize it +3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your customized client ### Completely custom HTTP client To use a completely custom HTTP client: 1. Replace your [`browserbase-java` dependency](#installation) with `browserbase-java-core` -2. Write a class that implements the [`HttpClient`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt) interface -3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your new client class +2. Write a class that implements the [`HttpClient`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt) interface +3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your new client class ## Undocumented API functionality @@ -426,8 +426,8 @@ The SDK is typed for convenient usage of the documented API. However, it also su To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class: ```java -import com.stagehand.api.core.JsonValue; -import com.stagehand.api.models.sessions.SessionStartParams; +import com.browserbase.api.core.JsonValue; +import com.browserbase.api.models.sessions.SessionStartParams; SessionStartParams params = SessionStartParams.builder() .putAdditionalHeader("Secret-Header", "42") @@ -441,8 +441,8 @@ These can be accessed on the built object later using the `_additionalHeaders()` To set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class: ```java -import com.stagehand.api.core.JsonValue; -import com.stagehand.api.models.sessions.SessionStartParams; +import com.browserbase.api.core.JsonValue; +import com.browserbase.api.models.sessions.SessionStartParams; SessionStartParams params = SessionStartParams.builder() .localBrowserLaunchOptions(SessionStartParams.LocalBrowserLaunchOptions.builder() @@ -453,21 +453,21 @@ SessionStartParams params = SessionStartParams.builder() These properties can be accessed on the nested built object later using the `_additionalProperties()` method. -To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) object to its setter: +To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) object to its setter: ```java -import com.stagehand.api.core.JsonValue; -import com.stagehand.api.models.sessions.SessionStartParams; +import com.browserbase.api.core.JsonValue; +import com.browserbase.api.models.sessions.SessionStartParams; SessionStartParams params = SessionStartParams.builder() .env(JsonValue.from(42)) .build(); ``` -The most straightforward way to create a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt) is using its `from(...)` method: +The most straightforward way to create a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) is using its `from(...)` method: ```java -import com.stagehand.api.core.JsonValue; +import com.browserbase.api.core.JsonValue; import java.util.List; import java.util.Map; @@ -505,11 +505,11 @@ JsonValue complexValue = JsonValue.from(Map.of( Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. -To forcibly omit a required parameter or property, pass [`JsonMissing`](browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt): +To forcibly omit a required parameter or property, pass [`JsonMissing`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt): ```java -import com.stagehand.api.core.JsonMissing; -import com.stagehand.api.models.sessions.SessionStartParams; +import com.browserbase.api.core.JsonMissing; +import com.browserbase.api.models.sessions.SessionStartParams; SessionStartParams params = SessionStartParams.builder() .env(JsonMissing.of()) @@ -521,7 +521,7 @@ SessionStartParams params = SessionStartParams.builder() To access undocumented response properties, call the `_additionalProperties()` method: ```java -import com.stagehand.api.core.JsonValue; +import com.browserbase.api.core.JsonValue; import java.util.Map; Map additionalProperties = client.sessions().start(params)._additionalProperties(); @@ -551,8 +551,8 @@ String result = secretPropertyValue.accept(new JsonValue.Visitor<>() { To access a property's raw JSON value, which may be undocumented, call its `_` prefixed method: ```java -import com.stagehand.api.core.JsonField; -import com.stagehand.api.models.sessions.SessionStartParams; +import com.browserbase.api.core.JsonField; +import com.browserbase.api.models.sessions.SessionStartParams; import java.util.Optional; JsonField env = client.sessions().start(params)._env(); @@ -575,12 +575,12 @@ if (env.isMissing()) { In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else. -By default, the SDK will not throw an exception in this case. It will throw [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt) only if you directly access the property. +By default, the SDK will not throw an exception in this case. It will throw [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt) only if you directly access the property. If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: ```java -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartResponse response = client.sessions().start(params).validate(); ``` @@ -588,7 +588,7 @@ SessionStartResponse response = client.sessions().start(params).validate(); Or configure the method call to validate the response using the `responseValidation` method: ```java -import com.stagehand.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartResponse response = client.sessions().start( params, RequestOptions.builder().responseValidation(true).build() @@ -598,8 +598,8 @@ SessionStartResponse response = client.sessions().start( Or configure the default for all method calls at the client level: ```java -import com.stagehand.api.client.BrowserbaseClient; -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; BrowserbaseClient client = BrowserbaseOkHttpClient.builder() .fromEnv() diff --git a/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt b/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt similarity index 95% rename from browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt rename to browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt index 5113c2c..dee001e 100644 --- a/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClient.kt +++ b/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt @@ -1,17 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.client.okhttp - +package com.browserbase.api.client.okhttp + +import com.browserbase.api.client.BrowserbaseClient +import com.browserbase.api.client.BrowserbaseClientImpl +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.Sleeper +import com.browserbase.api.core.Timeout +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.databind.json.JsonMapper -import com.stagehand.api.client.BrowserbaseClient -import com.stagehand.api.client.BrowserbaseClientImpl -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.Sleeper -import com.stagehand.api.core.Timeout -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.HttpClient -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.core.jsonMapper import java.net.Proxy import java.time.Clock import java.time.Duration @@ -116,7 +116,7 @@ class BrowserbaseOkHttpClient private constructor() { /** * The Jackson JSON mapper to use for serializing and deserializing JSON. * - * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and + * Defaults to [com.browserbase.api.core.jsonMapper]. The default is usually sufficient and * rarely needs to be overridden. */ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } diff --git a/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt b/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt similarity index 95% rename from browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt rename to browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt index bf6ef08..924eb97 100644 --- a/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt +++ b/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt @@ -1,17 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.client.okhttp - +package com.browserbase.api.client.okhttp + +import com.browserbase.api.client.BrowserbaseClientAsync +import com.browserbase.api.client.BrowserbaseClientAsyncImpl +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.Sleeper +import com.browserbase.api.core.Timeout +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.databind.json.JsonMapper -import com.stagehand.api.client.BrowserbaseClientAsync -import com.stagehand.api.client.BrowserbaseClientAsyncImpl -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.Sleeper -import com.stagehand.api.core.Timeout -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.HttpClient -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.core.jsonMapper import java.net.Proxy import java.time.Clock import java.time.Duration @@ -116,7 +116,7 @@ class BrowserbaseOkHttpClientAsync private constructor() { /** * The Jackson JSON mapper to use for serializing and deserializing JSON. * - * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and + * Defaults to [com.browserbase.api.core.jsonMapper]. The default is usually sufficient and * rarely needs to be overridden. */ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } diff --git a/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt b/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt similarity index 94% rename from browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt rename to browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index 14cfe6c..433919c 100644 --- a/browserbase-java-client-okhttp/src/main/kotlin/com/stagehand/api/client/okhttp/OkHttpClient.kt +++ b/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -1,14 +1,14 @@ -package com.stagehand.api.client.okhttp - -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.Timeout -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.HttpClient -import com.stagehand.api.core.http.HttpMethod -import com.stagehand.api.core.http.HttpRequest -import com.stagehand.api.core.http.HttpRequestBody -import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.errors.BrowserbaseIoException +package com.browserbase.api.client.okhttp + +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.Timeout +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.HttpMethod +import com.browserbase.api.core.http.HttpRequest +import com.browserbase.api.core.http.HttpRequestBody +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.errors.BrowserbaseIoException import java.io.IOException import java.io.InputStream import java.net.Proxy diff --git a/browserbase-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt b/browserbase-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt similarity index 90% rename from browserbase-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt rename to browserbase-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt index 950e323..3a39e9e 100644 --- a/browserbase-java-client-okhttp/src/test/kotlin/com/stagehand/api/client/okhttp/OkHttpClientTest.kt +++ b/browserbase-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt @@ -1,10 +1,10 @@ -package com.stagehand.api.client.okhttp +package com.browserbase.api.client.okhttp +import com.browserbase.api.core.http.HttpMethod +import com.browserbase.api.core.http.HttpRequest import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import com.stagehand.api.core.http.HttpMethod -import com.stagehand.api.core.http.HttpRequest import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt index 6e2b6a0..e77d3b1 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClient.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.client +package com.browserbase.api.client -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.services.blocking.SessionService +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.services.blocking.SessionService import java.util.function.Consumer /** diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt index aef1082..85a8cd5 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsync.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.client +package com.browserbase.api.client -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.services.async.SessionServiceAsync +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.services.async.SessionServiceAsync import java.util.function.Consumer /** diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt similarity index 88% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt index a7281d2..78e60db 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientAsyncImpl.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt @@ -1,11 +1,11 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.client +package com.browserbase.api.client -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.getPackageVersion -import com.stagehand.api.services.async.SessionServiceAsync -import com.stagehand.api.services.async.SessionServiceAsyncImpl +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.getPackageVersion +import com.browserbase.api.services.async.SessionServiceAsync +import com.browserbase.api.services.async.SessionServiceAsyncImpl import java.util.function.Consumer class BrowserbaseClientAsyncImpl(private val clientOptions: ClientOptions) : diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt similarity index 88% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt index afe65db..3df8a4f 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/client/BrowserbaseClientImpl.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt @@ -1,11 +1,11 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.client +package com.browserbase.api.client -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.getPackageVersion -import com.stagehand.api.services.blocking.SessionService -import com.stagehand.api.services.blocking.SessionServiceImpl +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.getPackageVersion +import com.browserbase.api.services.blocking.SessionService +import com.browserbase.api.services.blocking.SessionServiceImpl import java.util.function.Consumer class BrowserbaseClientImpl(private val clientOptions: ClientOptions) : BrowserbaseClient { diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt index 98c91bd..dc07be5 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseDeserializer.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.ObjectCodec diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt similarity index 84% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt index 929a990..9142bfe 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/BaseSerializer.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import com.fasterxml.jackson.databind.ser.std.StdSerializer import kotlin.reflect.KClass diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt similarity index 99% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt index 21ef979..0eb0c57 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Check.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt @@ -1,6 +1,6 @@ @file:JvmName("Check") -package com.stagehand.api.core +package com.browserbase.api.core import com.fasterxml.jackson.core.Version import com.fasterxml.jackson.core.util.VersionUtil diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 3cbfa6e..0032ba1 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ClientOptions.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -1,13 +1,13 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.core +package com.browserbase.api.core +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.PhantomReachableClosingHttpClient +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.http.RetryingHttpClient import com.fasterxml.jackson.databind.json.JsonMapper -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.HttpClient -import com.stagehand.api.core.http.PhantomReachableClosingHttpClient -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.core.http.RetryingHttpClient import java.time.Clock import java.time.Duration import java.util.Optional @@ -36,8 +36,8 @@ private constructor( /** * The Jackson JSON mapper to use for serializing and deserializing JSON. * - * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and rarely - * needs to be overridden. + * Defaults to [com.browserbase.api.core.jsonMapper]. The default is usually sufficient and + * rarely needs to be overridden. */ @get:JvmName("jsonMapper") val jsonMapper: JsonMapper, /** @@ -199,7 +199,7 @@ private constructor( /** * The Jackson JSON mapper to use for serializing and deserializing JSON. * - * Defaults to [com.stagehand.api.core.jsonMapper]. The default is usually sufficient and + * Defaults to [com.browserbase.api.core.jsonMapper]. The default is usually sufficient and * rarely needs to be overridden. */ fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt index 039a60c..7ea0449 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/DefaultSleeper.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import java.time.Duration import java.util.Timer diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt similarity index 99% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt index 29d99af..9ed574e 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/ObjectMappers.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt @@ -1,6 +1,6 @@ @file:JvmName("ObjectMappers") -package com.stagehand.api.core +package com.browserbase.api.core import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.core.JsonGenerator diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt similarity index 75% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt index 7f5a2f1..74e0357 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Params.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt @@ -1,7 +1,7 @@ -package com.stagehand.api.core +package com.browserbase.api.core -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams /** An interface representing parameters passed to a service method. */ interface Params { diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt index 648e916..5c5bb35 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachable.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt @@ -1,8 +1,8 @@ @file:JvmName("PhantomReachable") -package com.stagehand.api.core +package com.browserbase.api.core -import com.stagehand.api.errors.BrowserbaseException +import com.browserbase.api.errors.BrowserbaseException import java.lang.reflect.InvocationTargetException /** diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt index cc3cebb..7fb24a5 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableExecutorService.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import java.util.concurrent.Callable import java.util.concurrent.ExecutorService diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt index 8d82484..172760d 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PhantomReachableSleeper.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import java.time.Duration import java.util.concurrent.CompletableFuture diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt similarity index 90% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt index 0da40de..89ffa2d 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/PrepareRequest.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt @@ -1,8 +1,8 @@ @file:JvmName("PrepareRequest") -package com.stagehand.api.core +package com.browserbase.api.core -import com.stagehand.api.core.http.HttpRequest +import com.browserbase.api.core.http.HttpRequest import java.util.concurrent.CompletableFuture @JvmSynthetic diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt similarity index 92% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt index d24ffbe..bbd1121 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Properties.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt @@ -1,8 +1,8 @@ @file:JvmName("Properties") -package com.stagehand.api.core +package com.browserbase.api.core -import com.stagehand.api.client.BrowserbaseClient +import com.browserbase.api.client.BrowserbaseClient fun getOsArch(): String { val osArch = System.getProperty("os.arch") diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt index 10fb92a..9674a09 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/RequestOptions.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import java.time.Duration diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt index bccd778..7c5e93a 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Sleeper.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import java.time.Duration import java.util.concurrent.CompletableFuture diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt similarity index 99% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt index 23d9885..d5618ce 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Timeout.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.core +package com.browserbase.api.core import java.time.Duration import java.util.Objects diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt index 1e35e53..c772038 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Utils.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt @@ -1,8 +1,8 @@ @file:JvmName("Utils") -package com.stagehand.api.core +package com.browserbase.api.core -import com.stagehand.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.SortedMap import java.util.concurrent.CompletableFuture diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt similarity index 99% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt index e772b85..3eb4836 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/Values.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt @@ -1,5 +1,6 @@ -package com.stagehand.api.core +package com.browserbase.api.core +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JacksonAnnotationsInside import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonInclude @@ -24,7 +25,6 @@ import com.fasterxml.jackson.databind.node.JsonNodeType.OBJECT import com.fasterxml.jackson.databind.node.JsonNodeType.POJO import com.fasterxml.jackson.databind.node.JsonNodeType.STRING import com.fasterxml.jackson.databind.ser.std.NullSerializer -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.io.InputStream import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt similarity index 80% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt index 08b3c7f..bd5fff6 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/ErrorHandler.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt @@ -2,21 +2,21 @@ @file:JvmName("ErrorHandler") -package com.stagehand.api.core.handlers +package com.browserbase.api.core.handlers +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler +import com.browserbase.api.errors.BadRequestException +import com.browserbase.api.errors.InternalServerException +import com.browserbase.api.errors.NotFoundException +import com.browserbase.api.errors.PermissionDeniedException +import com.browserbase.api.errors.RateLimitException +import com.browserbase.api.errors.UnauthorizedException +import com.browserbase.api.errors.UnexpectedStatusCodeException +import com.browserbase.api.errors.UnprocessableEntityException import com.fasterxml.jackson.databind.json.JsonMapper -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.core.http.HttpResponse.Handler -import com.stagehand.api.errors.BadRequestException -import com.stagehand.api.errors.InternalServerException -import com.stagehand.api.errors.NotFoundException -import com.stagehand.api.errors.PermissionDeniedException -import com.stagehand.api.errors.RateLimitException -import com.stagehand.api.errors.UnauthorizedException -import com.stagehand.api.errors.UnexpectedStatusCodeException -import com.stagehand.api.errors.UnprocessableEntityException @JvmSynthetic internal fun errorBodyHandler(jsonMapper: JsonMapper): Handler { diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt similarity index 71% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt index 5ab311e..994a55e 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/JsonHandler.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt @@ -1,12 +1,12 @@ @file:JvmName("JsonHandler") -package com.stagehand.api.core.handlers +package com.browserbase.api.core.handlers +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.core.http.HttpResponse.Handler -import com.stagehand.api.errors.BrowserbaseInvalidDataException @JvmSynthetic internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler = diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt similarity index 66% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt index 9f7fb80..044de72 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/handlers/StringHandler.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt @@ -1,9 +1,9 @@ @file:JvmName("StringHandler") -package com.stagehand.api.core.handlers +package com.browserbase.api.core.handlers -import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.core.http.HttpResponse.Handler +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler @JvmSynthetic internal fun stringHandler(): Handler = StringHandlerInternal diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt index 23948e6..ccc5d24 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/AsyncStreamResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt @@ -1,6 +1,6 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http -import com.stagehand.api.core.http.AsyncStreamResponse.Handler +import com.browserbase.api.core.http.AsyncStreamResponse.Handler import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt similarity index 87% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt index a6bfeb9..edb40c4 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/Headers.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt @@ -1,16 +1,16 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.core.http - -import com.stagehand.api.core.JsonArray -import com.stagehand.api.core.JsonBoolean -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonNull -import com.stagehand.api.core.JsonNumber -import com.stagehand.api.core.JsonObject -import com.stagehand.api.core.JsonString -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.toImmutable +package com.browserbase.api.core.http + +import com.browserbase.api.core.JsonArray +import com.browserbase.api.core.JsonBoolean +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonNull +import com.browserbase.api.core.JsonNumber +import com.browserbase.api.core.JsonObject +import com.browserbase.api.core.JsonString +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.toImmutable import java.util.TreeMap class Headers diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt similarity index 89% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt index 45d1240..d5a84ec 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpClient.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt @@ -1,6 +1,6 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http -import com.stagehand.api.core.RequestOptions +import com.browserbase.api.core.RequestOptions import java.lang.AutoCloseable import java.util.concurrent.CompletableFuture diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt similarity index 76% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt index 243d075..fa2868d 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpMethod.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http enum class HttpMethod { GET, diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt index e262cfa..f42f44a 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequest.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt @@ -1,7 +1,7 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.toImmutable +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable class HttpRequest private constructor( diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt index 0066e15..05a1d50 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBodies.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt @@ -2,13 +2,13 @@ @file:JvmName("HttpRequestBodies") -package com.stagehand.api.core.http +package com.browserbase.api.core.http +import com.browserbase.api.core.MultipartField +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.node.JsonNodeType -import com.stagehand.api.core.MultipartField -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.io.InputStream import java.io.OutputStream import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt index 2b3f90a..57c20f4 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpRequestBody.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http import java.io.OutputStream import java.lang.AutoCloseable diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt similarity index 91% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt index 0fa2e44..045efac 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.core.http +package com.browserbase.api.core.http import java.io.InputStream diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt index 82b8717..91ba762 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/HttpResponseFor.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http import java.io.InputStream diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt similarity index 91% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt index 11f2997..13f1198 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt @@ -1,7 +1,7 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http -import com.stagehand.api.core.closeWhenPhantomReachable -import com.stagehand.api.core.http.AsyncStreamResponse.Handler +import com.browserbase.api.core.closeWhenPhantomReachable +import com.browserbase.api.core.http.AsyncStreamResponse.Handler import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt similarity index 84% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt index 52da985..54e1c00 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingHttpClient.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt @@ -1,7 +1,7 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.closeWhenPhantomReachable +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.closeWhenPhantomReachable import java.util.concurrent.CompletableFuture /** diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt similarity index 85% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt index b2f75a4..b977aab 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/PhantomReachableClosingStreamResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt @@ -1,6 +1,6 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http -import com.stagehand.api.core.closeWhenPhantomReachable +import com.browserbase.api.core.closeWhenPhantomReachable import java.util.stream.Stream /** diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt similarity index 90% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt index 114b89b..e394ad0 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/QueryParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt @@ -1,16 +1,16 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.core.http - -import com.stagehand.api.core.JsonArray -import com.stagehand.api.core.JsonBoolean -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonNull -import com.stagehand.api.core.JsonNumber -import com.stagehand.api.core.JsonObject -import com.stagehand.api.core.JsonString -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.toImmutable +package com.browserbase.api.core.http + +import com.browserbase.api.core.JsonArray +import com.browserbase.api.core.JsonBoolean +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonNull +import com.browserbase.api.core.JsonNumber +import com.browserbase.api.core.JsonObject +import com.browserbase.api.core.JsonString +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.toImmutable class QueryParams private constructor( diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt index 688ae4f..358057c 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/RetryingHttpClient.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt @@ -1,11 +1,11 @@ -package com.stagehand.api.core.http - -import com.stagehand.api.core.DefaultSleeper -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.Sleeper -import com.stagehand.api.core.checkRequired -import com.stagehand.api.errors.BrowserbaseIoException -import com.stagehand.api.errors.BrowserbaseRetryableException +package com.browserbase.api.core.http + +import com.browserbase.api.core.DefaultSleeper +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.Sleeper +import com.browserbase.api.core.checkRequired +import com.browserbase.api.errors.BrowserbaseIoException +import com.browserbase.api.errors.BrowserbaseRetryableException import java.io.IOException import java.time.Clock import java.time.Duration diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt similarity index 92% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt index ace181d..603e8bb 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/core/http/StreamResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http import java.util.stream.Stream diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt index 0df8b4a..8281e6d 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BadRequestException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt similarity index 80% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt index eb7f6e5..2b49c25 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.errors +package com.browserbase.api.errors open class BrowserbaseException @JvmOverloads diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt similarity index 81% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt index 8e9730d..28a9644 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseInvalidDataException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.errors +package com.browserbase.api.errors class BrowserbaseInvalidDataException @JvmOverloads diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt similarity index 81% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt index aa9c0de..6d8a71c 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseIoException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.errors +package com.browserbase.api.errors class BrowserbaseIoException @JvmOverloads diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt index 8984d2e..1754ee9 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseRetryableException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.errors +package com.browserbase.api.errors /** * Exception that indicates a transient error that can be retried. diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt similarity index 72% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt index d88ef6f..bb5c849 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/BrowserbaseServiceException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers abstract class BrowserbaseServiceException protected constructor(message: String, cause: Throwable? = null) : diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt index 6682cbf..3728e7d 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/InternalServerException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt similarity index 92% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt index cf2a3dc..5fe3abd 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/NotFoundException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt index 882f883..b161cb7 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/PermissionDeniedException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt index aedc3cf..cc270eb 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/RateLimitException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt index 5eff55d..bdbd3ef 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnauthorizedException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt index fa6913f..8b1a465 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnexpectedStatusCodeException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt index 1085120..6fc0a4c 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/errors/UnprocessableEntityException.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.errors +package com.browserbase.api.errors -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt index f071b0a..fd113b6 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/Action.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt @@ -1,19 +1,19 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkKnown -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 2d21ed5..51355b2 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/ModelConfig.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -1,17 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index eff4104..37b2123 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -1,7 +1,22 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -13,21 +28,6 @@ import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.BaseDeserializer -import com.stagehand.api.core.BaseSerializer -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.allMaxBy -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.getOrThrow -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt index f0d6751..f07a16d 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionActResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -1,19 +1,19 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkKnown -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index c559008..a3bb3fe 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -1,12 +1,12 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.core.toImmutable +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt index 59b3dc9..dd40544 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionEndResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -1,16 +1,16 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt index de2624a..570576f 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt @@ -1,7 +1,21 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -13,20 +27,6 @@ import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.BaseDeserializer -import com.stagehand.api.core.BaseSerializer -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.allMaxBy -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.getOrThrow -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt index 861033b..e126222 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt @@ -1,18 +1,18 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkKnown -import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index c6cd822..652ea48 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -1,21 +1,21 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index 912bbcb..2a8b52c 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionExtractResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -1,7 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.getOrThrow +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -13,16 +23,6 @@ import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.BaseDeserializer -import com.stagehand.api.core.BaseSerializer -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.allMaxBy -import com.stagehand.api.core.getOrThrow -import com.stagehand.api.core.toImmutable -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index bb111b3..f8dd95b 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -1,21 +1,21 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt index e570e58..28a15c2 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -1,16 +1,16 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 84d197c..802e3ea 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionObserveParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -1,20 +1,20 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt similarity index 98% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 0a52ee0..22ad279 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartParams.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -1,21 +1,21 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.Enum -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.Params -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.http.QueryParams -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects import java.util.Optional diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index e78188e..152fc44 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/models/sessions/SessionStartResponse.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -1,17 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions - +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.stagehand.api.core.ExcludeMissing -import com.stagehand.api.core.JsonField -import com.stagehand.api.core.JsonMissing -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.checkRequired -import com.stagehand.api.errors.BrowserbaseInvalidDataException import java.util.Collections import java.util.Objects diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index 12589d9..5c78924 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsync.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -1,24 +1,24 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services.async - -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.http.HttpResponseFor -import com.stagehand.api.models.sessions.Action -import com.stagehand.api.models.sessions.SessionActParams -import com.stagehand.api.models.sessions.SessionActResponse -import com.stagehand.api.models.sessions.SessionEndParams -import com.stagehand.api.models.sessions.SessionEndResponse -import com.stagehand.api.models.sessions.SessionExecuteAgentParams -import com.stagehand.api.models.sessions.SessionExecuteAgentResponse -import com.stagehand.api.models.sessions.SessionExtractParams -import com.stagehand.api.models.sessions.SessionExtractResponse -import com.stagehand.api.models.sessions.SessionNavigateParams -import com.stagehand.api.models.sessions.SessionNavigateResponse -import com.stagehand.api.models.sessions.SessionObserveParams -import com.stagehand.api.models.sessions.SessionStartParams -import com.stagehand.api.models.sessions.SessionStartResponse +package com.browserbase.api.services.async + +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.models.sessions.Action +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionStartParams +import com.browserbase.api.models.sessions.SessionStartResponse import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.function.Consumer diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt similarity index 89% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index a103a22..baa7114 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/async/SessionServiceAsyncImpl.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -1,35 +1,35 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services.async +package com.browserbase.api.services.async -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.handlers.errorBodyHandler -import com.stagehand.api.core.handlers.errorHandler -import com.stagehand.api.core.handlers.jsonHandler -import com.stagehand.api.core.http.HttpMethod -import com.stagehand.api.core.http.HttpRequest -import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.core.http.HttpResponse.Handler -import com.stagehand.api.core.http.HttpResponseFor -import com.stagehand.api.core.http.json -import com.stagehand.api.core.http.parseable -import com.stagehand.api.core.prepareAsync -import com.stagehand.api.models.sessions.Action -import com.stagehand.api.models.sessions.SessionActParams -import com.stagehand.api.models.sessions.SessionActResponse -import com.stagehand.api.models.sessions.SessionEndParams -import com.stagehand.api.models.sessions.SessionEndResponse -import com.stagehand.api.models.sessions.SessionExecuteAgentParams -import com.stagehand.api.models.sessions.SessionExecuteAgentResponse -import com.stagehand.api.models.sessions.SessionExtractParams -import com.stagehand.api.models.sessions.SessionExtractResponse -import com.stagehand.api.models.sessions.SessionNavigateParams -import com.stagehand.api.models.sessions.SessionNavigateResponse -import com.stagehand.api.models.sessions.SessionObserveParams -import com.stagehand.api.models.sessions.SessionStartParams -import com.stagehand.api.models.sessions.SessionStartResponse +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.handlers.errorBodyHandler +import com.browserbase.api.core.handlers.errorHandler +import com.browserbase.api.core.handlers.jsonHandler +import com.browserbase.api.core.http.HttpMethod +import com.browserbase.api.core.http.HttpRequest +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler +import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.core.http.json +import com.browserbase.api.core.http.parseable +import com.browserbase.api.core.prepareAsync +import com.browserbase.api.models.sessions.Action +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionStartParams +import com.browserbase.api.models.sessions.SessionStartResponse import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.function.Consumer diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index b605953..aac24dc 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionService.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -1,25 +1,25 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services.blocking - +package com.browserbase.api.services.blocking + +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.models.sessions.Action +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionStartParams +import com.browserbase.api.models.sessions.SessionStartResponse import com.google.errorprone.annotations.MustBeClosed -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.http.HttpResponseFor -import com.stagehand.api.models.sessions.Action -import com.stagehand.api.models.sessions.SessionActParams -import com.stagehand.api.models.sessions.SessionActResponse -import com.stagehand.api.models.sessions.SessionEndParams -import com.stagehand.api.models.sessions.SessionEndResponse -import com.stagehand.api.models.sessions.SessionExecuteAgentParams -import com.stagehand.api.models.sessions.SessionExecuteAgentResponse -import com.stagehand.api.models.sessions.SessionExtractParams -import com.stagehand.api.models.sessions.SessionExtractResponse -import com.stagehand.api.models.sessions.SessionNavigateParams -import com.stagehand.api.models.sessions.SessionNavigateResponse -import com.stagehand.api.models.sessions.SessionObserveParams -import com.stagehand.api.models.sessions.SessionStartParams -import com.stagehand.api.models.sessions.SessionStartResponse import java.util.Optional import java.util.function.Consumer diff --git a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt similarity index 88% rename from browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt rename to browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index f154a4a..6c09595 100644 --- a/browserbase-java-core/src/main/kotlin/com/stagehand/api/services/blocking/SessionServiceImpl.kt +++ b/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -1,35 +1,35 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services.blocking +package com.browserbase.api.services.blocking -import com.stagehand.api.core.ClientOptions -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.checkRequired -import com.stagehand.api.core.handlers.errorBodyHandler -import com.stagehand.api.core.handlers.errorHandler -import com.stagehand.api.core.handlers.jsonHandler -import com.stagehand.api.core.http.HttpMethod -import com.stagehand.api.core.http.HttpRequest -import com.stagehand.api.core.http.HttpResponse -import com.stagehand.api.core.http.HttpResponse.Handler -import com.stagehand.api.core.http.HttpResponseFor -import com.stagehand.api.core.http.json -import com.stagehand.api.core.http.parseable -import com.stagehand.api.core.prepare -import com.stagehand.api.models.sessions.Action -import com.stagehand.api.models.sessions.SessionActParams -import com.stagehand.api.models.sessions.SessionActResponse -import com.stagehand.api.models.sessions.SessionEndParams -import com.stagehand.api.models.sessions.SessionEndResponse -import com.stagehand.api.models.sessions.SessionExecuteAgentParams -import com.stagehand.api.models.sessions.SessionExecuteAgentResponse -import com.stagehand.api.models.sessions.SessionExtractParams -import com.stagehand.api.models.sessions.SessionExtractResponse -import com.stagehand.api.models.sessions.SessionNavigateParams -import com.stagehand.api.models.sessions.SessionNavigateResponse -import com.stagehand.api.models.sessions.SessionObserveParams -import com.stagehand.api.models.sessions.SessionStartParams -import com.stagehand.api.models.sessions.SessionStartResponse +import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.handlers.errorBodyHandler +import com.browserbase.api.core.handlers.errorHandler +import com.browserbase.api.core.handlers.jsonHandler +import com.browserbase.api.core.http.HttpMethod +import com.browserbase.api.core.http.HttpRequest +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler +import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.core.http.json +import com.browserbase.api.core.http.parseable +import com.browserbase.api.core.prepare +import com.browserbase.api.models.sessions.Action +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionStartParams +import com.browserbase.api.models.sessions.SessionStartResponse import java.util.Optional import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull diff --git a/browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro b/browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro index 246b6fe..474257e 100644 --- a/browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro +++ b/browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro @@ -22,11 +22,11 @@ -keep class * extends com.fasterxml.jackson.core.type.TypeReference { *; } # Jackson uses reflection to access our class serializers and deserializers. --keep @com.fasterxml.jackson.databind.annotation.JsonSerialize class com.stagehand.api.** { *; } --keep @com.fasterxml.jackson.databind.annotation.JsonDeserialize class com.stagehand.api.** { *; } +-keep @com.fasterxml.jackson.databind.annotation.JsonSerialize class com.browserbase.api.** { *; } +-keep @com.fasterxml.jackson.databind.annotation.JsonDeserialize class com.browserbase.api.** { *; } # Jackson uses reflection to serialize and deserialize our classes based on their constructors and annotated members. --keepclassmembers class com.stagehand.api.** { +-keepclassmembers class com.browserbase.api.** { (...); @com.fasterxml.jackson.annotation.* *; } \ No newline at end of file diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt index 47f81ce..d83abd1 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/TestServerExtension.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt @@ -1,4 +1,4 @@ -package com.stagehand.api +package com.browserbase.api import java.lang.RuntimeException import java.net.URL diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt similarity index 93% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt index 153fd8f..e73f724 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ClientOptionsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.core +package com.browserbase.api.core -import com.stagehand.api.core.http.HttpClient +import com.browserbase.api.core.http.HttpClient import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt similarity index 99% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt index d4a23d2..d405053 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ObjectMappersTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt similarity index 95% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt index f5cf23d..b1d98ae 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/PhantomReachableTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt similarity index 97% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt index b452f98..163e1a2 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/UtilsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt similarity index 99% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt index 4d5b67c..d098377 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/ValuesTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core +package com.browserbase.api.core import java.util.Optional import org.assertj.core.api.Assertions.assertThat diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt similarity index 99% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt index f30d55c..c5d8e71 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/AsyncStreamResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http import java.util.* import java.util.concurrent.CompletableFuture diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt similarity index 99% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt index dae2b71..81b7261 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/HeadersTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.params.ParameterizedTest diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt similarity index 99% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt index 1210beb..8d98e38 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/QueryParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt @@ -1,4 +1,4 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.params.ParameterizedTest diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt index 46bbd9f..3275b09 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/core/http/RetryingHttpClientTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt @@ -1,13 +1,13 @@ -package com.stagehand.api.core.http +package com.browserbase.api.core.http +import com.browserbase.api.client.okhttp.OkHttpClient +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.Sleeper +import com.browserbase.api.errors.BrowserbaseRetryableException import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.github.tomakehurst.wiremock.stubbing.Scenario -import com.stagehand.api.client.okhttp.OkHttpClient -import com.stagehand.api.core.RequestOptions -import com.stagehand.api.core.Sleeper -import com.stagehand.api.errors.BrowserbaseRetryableException import java.io.InputStream import java.time.Duration import java.util.concurrent.CompletableFuture diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt similarity index 94% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt index 6928e9f..fcd120c 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ActionTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.jsonMapper import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt similarity index 94% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index a1f75ab..0430aec 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/ModelConfigTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.jsonMapper import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt similarity index 97% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 921e718..fbcca00 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt similarity index 96% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt index 7723433..7f4d8c8 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionActResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.jsonMapper import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt similarity index 93% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 914b7d4..ab839e5 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt similarity index 91% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt index a5119d5..b52414c 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionEndResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.jsonMapper import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt index 532b194..6d0d59b 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt similarity index 91% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt index 9da3901..3fb7223 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExecuteAgentResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.jsonMapper import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt similarity index 97% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 67cdf9e..7df72a7 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt similarity index 94% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt index 9615580..c11f3f5 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionExtractResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt @@ -1,11 +1,11 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.jsonMapper +import com.browserbase.api.errors.BrowserbaseInvalidDataException import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.jsonMapper -import com.stagehand.api.errors.BrowserbaseInvalidDataException import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt similarity index 97% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt index 6550c8e..fe762db 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt similarity index 92% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt index 2ba7257..1385964 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionNavigateResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.jsonMapper import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 6a3347f..a8ab677 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionObserveParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions -import com.stagehand.api.core.http.Headers +import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 9c70b5b..1c7e4d8 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt similarity index 93% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt index 0ddd138..714c73d 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/models/sessions/SessionStartResponseTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.models.sessions +package com.browserbase.api.models.sessions +import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.core.jsonMapper import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt similarity index 96% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 8fc0701..d9c176d 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ErrorHandlingTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -1,28 +1,28 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services - +package com.browserbase.api.services + +import com.browserbase.api.client.BrowserbaseClient +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper +import com.browserbase.api.errors.BadRequestException +import com.browserbase.api.errors.BrowserbaseException +import com.browserbase.api.errors.InternalServerException +import com.browserbase.api.errors.NotFoundException +import com.browserbase.api.errors.PermissionDeniedException +import com.browserbase.api.errors.RateLimitException +import com.browserbase.api.errors.UnauthorizedException +import com.browserbase.api.errors.UnexpectedStatusCodeException +import com.browserbase.api.errors.UnprocessableEntityException +import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.post import com.github.tomakehurst.wiremock.client.WireMock.status import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import com.stagehand.api.client.BrowserbaseClient -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient -import com.stagehand.api.core.JsonValue -import com.stagehand.api.core.http.Headers -import com.stagehand.api.core.jsonMapper -import com.stagehand.api.errors.BadRequestException -import com.stagehand.api.errors.BrowserbaseException -import com.stagehand.api.errors.InternalServerException -import com.stagehand.api.errors.NotFoundException -import com.stagehand.api.errors.PermissionDeniedException -import com.stagehand.api.errors.RateLimitException -import com.stagehand.api.errors.UnauthorizedException -import com.stagehand.api.errors.UnexpectedStatusCodeException -import com.stagehand.api.errors.UnprocessableEntityException -import com.stagehand.api.models.sessions.SessionStartParams import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.entry import org.junit.jupiter.api.BeforeEach diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt similarity index 90% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 76f9dd5..1fdec72 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/ServiceParamsTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -1,7 +1,11 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services +package com.browserbase.api.services +import com.browserbase.api.client.BrowserbaseClient +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.equalTo import com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath @@ -12,10 +16,6 @@ import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.client.WireMock.verify import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import com.stagehand.api.client.BrowserbaseClient -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient -import com.stagehand.api.core.JsonValue -import com.stagehand.api.models.sessions.SessionStartParams import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt similarity index 93% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index e01497b..64260cb 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/async/SessionServiceAsyncTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -1,17 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services.async +package com.browserbase.api.services.async -import com.stagehand.api.TestServerExtension -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClientAsync -import com.stagehand.api.core.JsonValue -import com.stagehand.api.models.sessions.ModelConfig -import com.stagehand.api.models.sessions.SessionActParams -import com.stagehand.api.models.sessions.SessionExecuteAgentParams -import com.stagehand.api.models.sessions.SessionExtractParams -import com.stagehand.api.models.sessions.SessionNavigateParams -import com.stagehand.api.models.sessions.SessionObserveParams -import com.stagehand.api.models.sessions.SessionStartParams +import com.browserbase.api.TestServerExtension +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClientAsync +import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.ModelConfig +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionStartParams import kotlin.jvm.optionals.getOrNull import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test diff --git a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt similarity index 93% rename from browserbase-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt rename to browserbase-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index e0d7f43..cbd77b3 100644 --- a/browserbase-java-core/src/test/kotlin/com/stagehand/api/services/blocking/SessionServiceTest.kt +++ b/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -1,17 +1,17 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.services.blocking - -import com.stagehand.api.TestServerExtension -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient -import com.stagehand.api.core.JsonValue -import com.stagehand.api.models.sessions.ModelConfig -import com.stagehand.api.models.sessions.SessionActParams -import com.stagehand.api.models.sessions.SessionExecuteAgentParams -import com.stagehand.api.models.sessions.SessionExtractParams -import com.stagehand.api.models.sessions.SessionNavigateParams -import com.stagehand.api.models.sessions.SessionObserveParams -import com.stagehand.api.models.sessions.SessionStartParams +package com.browserbase.api.services.blocking + +import com.browserbase.api.TestServerExtension +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.ModelConfig +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionStartParams import kotlin.jvm.optionals.getOrNull import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test diff --git a/browserbase-java-proguard-test/build.gradle.kts b/browserbase-java-proguard-test/build.gradle.kts index 4d0189d..4226829 100644 --- a/browserbase-java-proguard-test/build.gradle.kts +++ b/browserbase-java-proguard-test/build.gradle.kts @@ -59,7 +59,7 @@ val testProGuard by tasks.registering(JavaExec::class) { dependsOn(proguardJar) notCompatibleWithConfigurationCache("ProGuard") - mainClass.set("com.stagehand.api.proguard.ProGuardCompatibilityTest") + mainClass.set("com.browserbase.api.proguard.ProGuardCompatibilityTest") classpath = files(proguardJarPath) } @@ -89,7 +89,7 @@ val testR8 by tasks.registering(JavaExec::class) { dependsOn(r8Jar) notCompatibleWithConfigurationCache("R8") - mainClass.set("com.stagehand.api.proguard.ProGuardCompatibilityTest") + mainClass.set("com.browserbase.api.proguard.ProGuardCompatibilityTest") classpath = files(r8JarPath) } diff --git a/browserbase-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt b/browserbase-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt similarity index 91% rename from browserbase-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt rename to browserbase-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 82fd595..73126fc 100644 --- a/browserbase-java-proguard-test/src/test/kotlin/com/stagehand/api/proguard/ProGuardCompatibilityTest.kt +++ b/browserbase-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -1,12 +1,12 @@ // File generated from our OpenAPI spec by Stainless. -package com.stagehand.api.proguard +package com.browserbase.api.proguard +import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.core.jsonMapper +import com.browserbase.api.models.sessions.Action +import com.browserbase.api.models.sessions.SessionExtractResponse import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.stagehand.api.client.okhttp.BrowserbaseOkHttpClient -import com.stagehand.api.core.jsonMapper -import com.stagehand.api.models.sessions.Action -import com.stagehand.api.models.sessions.SessionExtractResponse import kotlin.reflect.full.memberFunctions import kotlin.reflect.jvm.javaMethod import org.assertj.core.api.Assertions.assertThat diff --git a/browserbase-java-proguard-test/test.pro b/browserbase-java-proguard-test/test.pro index 3db213a..47be604 100644 --- a/browserbase-java-proguard-test/test.pro +++ b/browserbase-java-proguard-test/test.pro @@ -1,5 +1,5 @@ # Specify the entrypoint where ProGuard starts to determine what's reachable. --keep class com.stagehand.api.proguard.** { *; } +-keep class com.browserbase.api.proguard.** { *; } # For the testing framework. -keep class org.junit.** { *; } diff --git a/build.gradle.kts b/build.gradle.kts index 2fffcae..471d362 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { } allprojects { - group = "com.stagehand.api" + group = "com.browserbase.api" version = "0.0.1" // x-release-please-version } From eda810c52371d131fe1006647dc3839f8d4b1ceb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:18:22 +0000 Subject: [PATCH 012/164] feat(api): manual updates --- .github/workflows/publish-sonatype.yml | 8 +- .github/workflows/release-doctor.yml | 8 +- .stats.yml | 2 +- LICENSE | 2 +- README.md | 192 +++++++++--------- SECURITY.md | 2 +- build.gradle.kts | 2 +- ...a.gradle.kts => stagehand.java.gradle.kts} | 0 ...gradle.kts => stagehand.kotlin.gradle.kts} | 2 +- ...radle.kts => stagehand.publish.gradle.kts} | 4 +- settings.gradle.kts | 4 +- .../build.gradle.kts | 6 +- .../api/client/okhttp/OkHttpClient.kt | 8 +- .../client/okhttp/StagehandOkHttpClient.kt | 20 +- .../okhttp/StagehandOkHttpClientAsync.kt | 20 +- .../api/client/okhttp/OkHttpClientTest.kt | 0 .../build.gradle.kts | 6 +- .../browserbase/api/client/StagehandClient.kt | 14 +- .../api/client/StagehandClientAsync.kt | 13 +- .../api/client/StagehandClientAsyncImpl.kt | 21 +- .../api/client/StagehandClientImpl.kt | 20 +- .../browserbase/api/core/BaseDeserializer.kt | 0 .../browserbase/api/core/BaseSerializer.kt | 0 .../kotlin/com/browserbase/api/core/Check.kt | 0 .../com/browserbase/api/core/ClientOptions.kt | 23 ++- .../browserbase/api/core/DefaultSleeper.kt | 0 .../com/browserbase/api/core/ObjectMappers.kt | 0 .../kotlin/com/browserbase/api/core/Params.kt | 0 .../browserbase/api/core/PhantomReachable.kt | 4 +- .../core/PhantomReachableExecutorService.kt | 0 .../api/core/PhantomReachableSleeper.kt | 0 .../browserbase/api/core/PrepareRequest.kt | 0 .../com/browserbase/api/core/Properties.kt | 4 +- .../browserbase/api/core/RequestOptions.kt | 0 .../com/browserbase/api/core/Sleeper.kt | 0 .../com/browserbase/api/core/Timeout.kt | 0 .../kotlin/com/browserbase/api/core/Utils.kt | 4 +- .../kotlin/com/browserbase/api/core/Values.kt | 12 +- .../api/core/handlers/ErrorHandler.kt | 0 .../api/core/handlers/JsonHandler.kt | 4 +- .../api/core/handlers/StringHandler.kt | 0 .../api/core/http/AsyncStreamResponse.kt | 0 .../com/browserbase/api/core/http/Headers.kt | 0 .../browserbase/api/core/http/HttpClient.kt | 0 .../browserbase/api/core/http/HttpMethod.kt | 0 .../browserbase/api/core/http/HttpRequest.kt | 0 .../api/core/http/HttpRequestBodies.kt | 6 +- .../api/core/http/HttpRequestBody.kt | 0 .../browserbase/api/core/http/HttpResponse.kt | 0 .../api/core/http/HttpResponseFor.kt | 0 ...ntomReachableClosingAsyncStreamResponse.kt | 0 .../http/PhantomReachableClosingHttpClient.kt | 0 .../PhantomReachableClosingStreamResponse.kt | 0 .../browserbase/api/core/http/QueryParams.kt | 0 .../api/core/http/RetryingHttpClient.kt | 8 +- .../api/core/http/StreamResponse.kt | 0 .../api/errors/BadRequestException.kt | 2 +- .../api/errors/InternalServerException.kt | 2 +- .../api/errors/NotFoundException.kt | 2 +- .../api/errors/PermissionDeniedException.kt | 2 +- .../api/errors/RateLimitException.kt | 2 +- .../api/errors/StagehandException.kt | 2 +- .../errors/StagehandInvalidDataException.kt | 5 +- .../api/errors/StagehandIoException.kt | 5 +- .../api/errors/StagehandRetryableException.kt | 5 +- .../api/errors/StagehandServiceException.kt | 4 +- .../api/errors/UnauthorizedException.kt | 2 +- .../errors/UnexpectedStatusCodeException.kt | 2 +- .../errors/UnprocessableEntityException.kt | 2 +- .../browserbase/api/models/sessions/Action.kt | 14 +- .../api/models/sessions/ModelConfig.kt | 22 +- .../api/models/sessions/SessionActParams.kt | 42 ++-- .../api/models/sessions/SessionActResponse.kt | 10 +- .../api/models/sessions/SessionEndParams.kt | 0 .../api/models/sessions/SessionEndResponse.kt | 6 +- .../sessions/SessionExecuteAgentParams.kt | 62 +++--- .../sessions/SessionExecuteAgentResponse.kt | 8 +- .../models/sessions/SessionExtractParams.kt | 40 ++-- .../models/sessions/SessionExtractResponse.kt | 14 +- .../models/sessions/SessionNavigateParams.kt | 42 ++-- .../sessions/SessionNavigateResponse.kt | 10 +- .../models/sessions/SessionObserveParams.kt | 34 ++-- .../api/models/sessions/SessionStartParams.kt | 54 ++--- .../models/sessions/SessionStartResponse.kt | 8 +- .../api/services/async/SessionServiceAsync.kt | 0 .../services/async/SessionServiceAsyncImpl.kt | 0 .../api/services/blocking/SessionService.kt | 0 .../services/blocking/SessionServiceImpl.kt | 0 .../META-INF/proguard/stagehand-java-core.pro | 0 .../browserbase/api/TestServerExtension.kt | 0 .../browserbase/api/core/ClientOptionsTest.kt | 0 .../browserbase/api/core/ObjectMappersTest.kt | 0 .../api/core/PhantomReachableTest.kt | 0 .../com/browserbase/api/core/UtilsTest.kt | 0 .../com/browserbase/api/core/ValuesTest.kt | 0 .../api/core/http/AsyncStreamResponseTest.kt | 0 .../browserbase/api/core/http/HeadersTest.kt | 0 .../api/core/http/QueryParamsTest.kt | 0 .../api/core/http/RetryingHttpClientTest.kt | 6 +- .../api/models/sessions/ActionTest.kt | 0 .../api/models/sessions/ModelConfigTest.kt | 0 .../models/sessions/SessionActParamsTest.kt | 0 .../models/sessions/SessionActResponseTest.kt | 0 .../models/sessions/SessionEndParamsTest.kt | 0 .../models/sessions/SessionEndResponseTest.kt | 0 .../sessions/SessionExecuteAgentParamsTest.kt | 0 .../SessionExecuteAgentResponseTest.kt | 0 .../sessions/SessionExtractParamsTest.kt | 0 .../sessions/SessionExtractResponseTest.kt | 4 +- .../sessions/SessionNavigateParamsTest.kt | 0 .../sessions/SessionNavigateResponseTest.kt | 0 .../sessions/SessionObserveParamsTest.kt | 0 .../models/sessions/SessionStartParamsTest.kt | 0 .../sessions/SessionStartResponseTest.kt | 0 .../api/services/ErrorHandlingTest.kt | 12 +- .../api/services/ServiceParamsTest.kt | 8 +- .../services/async/SessionServiceAsyncTest.kt | 16 +- .../services/blocking/SessionServiceTest.kt | 16 +- .../build.gradle.kts | 8 +- .../api/proguard/ProGuardCompatibilityTest.kt | 6 +- .../test.pro | 0 .../build.gradle.kts | 6 +- 122 files changed, 449 insertions(+), 455 deletions(-) rename buildSrc/src/main/kotlin/{browserbase.java.gradle.kts => stagehand.java.gradle.kts} (100%) rename buildSrc/src/main/kotlin/{browserbase.kotlin.gradle.kts => stagehand.kotlin.gradle.kts} (99%) rename buildSrc/src/main/kotlin/{browserbase.publish.gradle.kts => stagehand.publish.gradle.kts} (95%) rename {browserbase-java-client-okhttp => stagehand-java-client-okhttp}/build.gradle.kts (76%) rename {browserbase-java-client-okhttp => stagehand-java-client-okhttp}/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt (96%) rename browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt => stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt (95%) rename browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt => stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt (95%) rename {browserbase-java-client-okhttp => stagehand-java-client-okhttp}/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/build.gradle.kts (93%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClient.kt (85%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsync.kt (87%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt (69%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt (69%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Check.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt (94%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Params.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt (92%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Properties.kt (88%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Sleeper.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Timeout.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Utils.kt (96%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/Values.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt (80%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/Headers.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt (96%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt (97%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandException.kt (82%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt (58%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandIoException.kt (61%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandRetryableException.kt (85%) rename browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt => stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandServiceException.kt (80%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt (97%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt (93%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt (96%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt (96%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt (94%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt (94%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt (100%) rename browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro => stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/TestServerExtension.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt (98%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt (100%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt (98%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt (92%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt (95%) rename {browserbase-java-core => stagehand-java-core}/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt (95%) rename {browserbase-java-proguard-test => stagehand-java-proguard-test}/build.gradle.kts (90%) rename {browserbase-java-proguard-test => stagehand-java-proguard-test}/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt (93%) rename {browserbase-java-proguard-test => stagehand-java-proguard-test}/test.pro (100%) rename {browserbase-java => stagehand-java}/build.gradle.kts (85%) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index f40e546..6a27d98 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -35,7 +35,7 @@ jobs: GPG_SIGNING_KEY_ID="$(gpg --with-colons --list-keys | awk -F : -- '/^pub:/ { getline; print "0x" substr($10, length($10) - 7) }')" ./gradlew publish --no-configuration-cache env: - SONATYPE_USERNAME: ${{ secrets.BROWSERBASE_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file + SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} \ No newline at end of file diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index aac0446..a6e0235 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -18,7 +18,7 @@ jobs: run: | bash ./bin/check-release-environment env: - SONATYPE_USERNAME: ${{ secrets.BROWSERBASE_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} - SONATYPE_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} - GPG_SIGNING_KEY: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} - GPG_SIGNING_PASSWORD: ${{ secrets.BROWSERBASE_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} + SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} + GPG_SIGNING_KEY: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_KEY || secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_GPG_SIGNING_PASSWORD || secrets.GPG_SIGNING_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index ae2d02d..8741890 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 905fc70fd4344c8631aab6754bffd883 +config_hash: 1de7cb9bd4dc46fe3e20b637bc534908 diff --git a/LICENSE b/LICENSE index 2cec9d4..6b24314 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Browserbase + Copyright 2025 Stagehand Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 390f269..8453788 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -# Browserbase Java API Library +# Stagehand Java API Library -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/browserbase-java)](https://central.sonatype.com/artifact/com.browserbase.api/browserbase-java/0.0.1) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/browserbase-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/browserbase-java/0.0.1) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.0.1) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.0.1) -The Browserbase Java SDK provides convenient access to the [Browserbase REST API](https://browserbase.com) from applications written in Java. +The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://docs.stagehand.dev) from applications written in Java. It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [browserbase.com](https://browserbase.com). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/browserbase-java/0.0.1). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.0.1). @@ -24,7 +24,7 @@ The REST API documentation can be found on [browserbase.com](https://browserbase ### Gradle ```kotlin -implementation("com.browserbase.api:browserbase-java:0.0.1") +implementation("com.browserbase.api:stagehand-java:0.0.1") ``` ### Maven @@ -32,7 +32,7 @@ implementation("com.browserbase.api:browserbase-java:0.0.1") ```xml com.browserbase.api - browserbase-java + stagehand-java 0.0.1 ``` @@ -46,14 +46,14 @@ This library requires Java 8 or later. ## Usage ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; -// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables -BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -66,21 +66,21 @@ SessionStartResponse response = client.sessions().start(params); Configure the client using system properties or environment variables: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables -BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.fromEnv(); ``` Or manually: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .apiKey("My API Key") .build(); ``` @@ -88,12 +88,12 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() Or using a combination of the two approaches: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() - // Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties - // Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.builder() + // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties + // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables .fromEnv() .apiKey("My API Key") .build(); @@ -101,10 +101,10 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() See this table for the available options: -| Setter | System property | Environment variable | Required | Default value | -| --------- | ----------------------------- | ---------------------- | -------- | -------------------------------------------- | -| `apiKey` | `browserbase.stagehandApiKey` | `STAGEHAND_API_KEY` | true | - | -| `baseUrl` | `browserbase.baseUrl` | `BROWSERBASE_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | +| Setter | System property | Environment variable | Required | Default value | +| --------- | ------------------- | -------------------- | -------- | -------------------------------------------- | +| `apiKey` | `stagehand.apiKey` | `STAGEHAND_API_KEY` | true | - | +| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | System properties take precedence over environment variables. @@ -117,9 +117,9 @@ System properties take precedence over environment variables. To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service: ```java -import com.browserbase.api.client.BrowserbaseClient; +import com.browserbase.api.client.StagehandClient; -BrowserbaseClient clientWithOptions = client.withOptions(optionsBuilder -> { +StagehandClient clientWithOptions = client.withOptions(optionsBuilder -> { optionsBuilder.baseUrl("https://example.com"); optionsBuilder.maxRetries(42); }); @@ -129,7 +129,7 @@ The `withOptions()` method does not affect the original client or service. ## Requests and responses -To send a request to the Browserbase API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. +To send a request to the Stagehand API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. For example, `client.sessions().start(...)` should be called with an instance of `SessionStartParams`, and it will return an instance of `SessionStartResponse`. @@ -146,15 +146,15 @@ Because each class is immutable, builder modification will _never_ affect alread The default client is synchronous. To switch to asynchronous execution, call the `async()` method: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; -// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables -BrowserbaseClient client = BrowserbaseOkHttpClient.fromEnv(); +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -165,15 +165,15 @@ CompletableFuture response = client.async().sessions().sta Or create an asynchronous client from the beginning: ```java -import com.browserbase.api.client.BrowserbaseClientAsync; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClientAsync; +import com.browserbase.api.client.StagehandClientAsync; +import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync; import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; -// Configures using the `browserbase.stagehandApiKey` and `browserbase.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `BROWSERBASE_BASE_URL` environment variables -BrowserbaseClientAsync client = BrowserbaseOkHttpClientAsync.fromEnv(); +// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties +// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); SessionStartParams params = SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) @@ -216,46 +216,46 @@ SessionStartResponse parsedResponse = response.parse(); The SDK throws custom unchecked exception types: -- [`BrowserbaseServiceException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: +- [`StagehandServiceException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: - | Status | Exception | - | ------ | ------------------------------------------------------------------------------------------------------------------------------------ | - | 400 | [`BadRequestException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt) | - | 401 | [`UnauthorizedException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt) | - | 403 | [`PermissionDeniedException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt) | - | 404 | [`NotFoundException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt) | - | 422 | [`UnprocessableEntityException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt) | - | 429 | [`RateLimitException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt) | - | 5xx | [`InternalServerException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt) | - | others | [`UnexpectedStatusCodeException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt) | + | Status | Exception | + | ------ | ---------------------------------------------------------------------------------------------------------------------------------- | + | 400 | [`BadRequestException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt) | + | 401 | [`UnauthorizedException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt) | + | 403 | [`PermissionDeniedException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt) | + | 404 | [`NotFoundException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt) | + | 422 | [`UnprocessableEntityException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt) | + | 429 | [`RateLimitException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt) | + | 5xx | [`InternalServerException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt) | + | others | [`UnexpectedStatusCodeException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt) | -- [`BrowserbaseIoException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt): I/O networking errors. +- [`StagehandIoException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandIoException.kt): I/O networking errors. -- [`BrowserbaseRetryableException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt): Generic error indicating a failure that could be retried by the client. +- [`StagehandRetryableException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandRetryableException.kt): Generic error indicating a failure that could be retried by the client. -- [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. +- [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. -- [`BrowserbaseException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. +- [`StagehandException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. ## Logging The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). -Enable logging by setting the `BROWSERBASE_LOG` environment variable to `info`: +Enable logging by setting the `STAGEHAND_LOG` environment variable to `info`: ```sh -export BROWSERBASE_LOG=info +export STAGEHAND_LOG=info ``` Or to `debug` for more verbose logging: ```sh -export BROWSERBASE_LOG=debug +export STAGEHAND_LOG=debug ``` ## ProGuard and R8 -Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `browserbase-java-core` is published with a [configuration file](browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). +Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `stagehand-java-core` is published with a [configuration file](stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary. @@ -265,7 +265,7 @@ The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON seri The SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config). -If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt). +If the SDK threw an exception, but you're _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt). > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. @@ -289,10 +289,10 @@ The API may also explicitly instruct the SDK to retry or not retry a request. To set a custom number of retries, configure the client using the `maxRetries` method: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .fromEnv() .maxRetries(4) .build(); @@ -315,11 +315,11 @@ SessionStartResponse response = client.sessions().start( Or configure the default for all method calls at the client level: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; import java.time.Duration; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .fromEnv() .timeout(Duration.ofSeconds(30)) .build(); @@ -330,12 +330,12 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() To route requests through a proxy, configure the client using the `proxy` method: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; import java.net.InetSocketAddress; import java.net.Proxy; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .fromEnv() .proxy(new Proxy( Proxy.Type.HTTP, new InetSocketAddress( @@ -354,10 +354,10 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .fromEnv() // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa. .sslSocketFactory(yourSSLSocketFactory) @@ -371,10 +371,10 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() The SDK sends requests to the production by default. To send requests to a different environment, configure the client like so: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .fromEnv() // Other options include `local` .dev() @@ -385,15 +385,15 @@ BrowserbaseClient client = BrowserbaseOkHttpClient.builder() The SDK consists of three artifacts: -- `browserbase-java-core` +- `stagehand-java-core` - Contains core SDK logic - Does not depend on [OkHttp](https://square.github.io/okhttp) - - Exposes [`BrowserbaseClient`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt), [`BrowserbaseClientAsync`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt), [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt), and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), all of which can work with any HTTP client -- `browserbase-java-client-okhttp` + - Exposes [`StagehandClient`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClient.kt), [`StagehandClientAsync`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsync.kt), [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt), and [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt), all of which can work with any HTTP client +- `stagehand-java-client-okhttp` - Depends on [OkHttp](https://square.github.io/okhttp) - - Exposes [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) and [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), which provide a way to construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt) and [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), respectively, using OkHttp -- `browserbase-java` - - Depends on and exposes the APIs of both `browserbase-java-core` and `browserbase-java-client-okhttp` + - Exposes [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt) and [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt), which provide a way to construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt) and [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt), respectively, using OkHttp +- `stagehand-java` + - Depends on and exposes the APIs of both `stagehand-java-core` and `stagehand-java-client-okhttp` - Does not have its own logic This structure allows replacing the SDK's default HTTP client without pulling in unnecessary dependencies. @@ -405,17 +405,17 @@ This structure allows replacing the SDK's default HTTP client without pulling in To use a customized `OkHttpClient`: -1. Replace your [`browserbase-java` dependency](#installation) with `browserbase-java-core` -2. Copy `browserbase-java-client-okhttp`'s [`OkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt) class into your code and customize it -3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your customized client +1. Replace your [`stagehand-java` dependency](#installation) with `stagehand-java-core` +2. Copy `stagehand-java-client-okhttp`'s [`OkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt) class into your code and customize it +3. Construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt) or [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt), similarly to [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt), using your customized client ### Completely custom HTTP client To use a completely custom HTTP client: -1. Replace your [`browserbase-java` dependency](#installation) with `browserbase-java-core` -2. Write a class that implements the [`HttpClient`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt) interface -3. Construct [`BrowserbaseClientImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt) or [`BrowserbaseClientAsyncImpl`](browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt), similarly to [`BrowserbaseOkHttpClient`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt) or [`BrowserbaseOkHttpClientAsync`](browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt), using your new client class +1. Replace your [`stagehand-java` dependency](#installation) with `stagehand-java-core` +2. Write a class that implements the [`HttpClient`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt) interface +3. Construct [`StagehandClientImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt) or [`StagehandClientAsyncImpl`](stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt), similarly to [`StagehandOkHttpClient`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt) or [`StagehandOkHttpClientAsync`](stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt), using your new client class ## Undocumented API functionality @@ -453,7 +453,7 @@ SessionStartParams params = SessionStartParams.builder() These properties can be accessed on the nested built object later using the `_additionalProperties()` method. -To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) object to its setter: +To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) object to its setter: ```java import com.browserbase.api.core.JsonValue; @@ -464,7 +464,7 @@ SessionStartParams params = SessionStartParams.builder() .build(); ``` -The most straightforward way to create a [`JsonValue`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) is using its `from(...)` method: +The most straightforward way to create a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) is using its `from(...)` method: ```java import com.browserbase.api.core.JsonValue; @@ -505,7 +505,7 @@ JsonValue complexValue = JsonValue.from(Map.of( Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. -To forcibly omit a required parameter or property, pass [`JsonMissing`](browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt): +To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt): ```java import com.browserbase.api.core.JsonMissing; @@ -575,7 +575,7 @@ if (env.isMissing()) { In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else. -By default, the SDK will not throw an exception in this case. It will throw [`BrowserbaseInvalidDataException`](browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt) only if you directly access the property. +By default, the SDK will not throw an exception in this case. It will throw [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt) only if you directly access the property. If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: @@ -598,10 +598,10 @@ SessionStartResponse response = client.sessions().start( Or configure the default for all method calls at the client level: ```java -import com.browserbase.api.client.BrowserbaseClient; -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient; +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -BrowserbaseClient client = BrowserbaseOkHttpClient.builder() +StagehandClient client = StagehandOkHttpClient.builder() .fromEnv() .responseValidation(true) .build(); diff --git a/SECURITY.md b/SECURITY.md index be1c2db..dcfc419 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,7 +16,7 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Browserbase, please follow the respective company's security reporting guidelines. +or products provided by Stagehand, please follow the respective company's security reporting guidelines. --- diff --git a/build.gradle.kts b/build.gradle.kts index 471d362..0913290 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,7 +32,7 @@ subprojects { // Avoid race conditions between `dokkaJavadocCollector` and `dokkaJavadocJar` tasks tasks.named("dokkaJavadocCollector").configure { subprojects.flatMap { it.tasks } - .filter { it.project.name != "browserbase-java" && it.name == "dokkaJavadocJar" } + .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } diff --git a/buildSrc/src/main/kotlin/browserbase.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts similarity index 100% rename from buildSrc/src/main/kotlin/browserbase.java.gradle.kts rename to buildSrc/src/main/kotlin/stagehand.java.gradle.kts diff --git a/buildSrc/src/main/kotlin/browserbase.kotlin.gradle.kts b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts similarity index 99% rename from buildSrc/src/main/kotlin/browserbase.kotlin.gradle.kts rename to buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts index 08574e8..f3f48d1 100644 --- a/buildSrc/src/main/kotlin/browserbase.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts @@ -2,7 +2,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinVersion plugins { - id("browserbase.java") + id("stagehand.java") kotlin("jvm") } diff --git a/buildSrc/src/main/kotlin/browserbase.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts similarity index 95% rename from buildSrc/src/main/kotlin/browserbase.publish.gradle.kts rename to buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index 6822ae8..9f64944 100644 --- a/buildSrc/src/main/kotlin/browserbase.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -11,7 +11,7 @@ configure { pom { name.set("Stagehand P2P Server API") description.set("HTTP API for remote Stagehand browser automation. This API allows clients to\nconnect to a Stagehand server and execute browser automation tasks remotely.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.") - url.set("https://browserbase.com") + url.set("https://docs.stagehand.dev") licenses { license { @@ -21,7 +21,7 @@ configure { developers { developer { - name.set("Browserbase") + name.set("Stagehand") } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 53191ab..02623dd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,11 +1,11 @@ -rootProject.name = "browserbase-java-root" +rootProject.name = "stagehand-java-root" val projectNames = rootDir.listFiles() ?.asSequence() .orEmpty() .filter { file -> file.isDirectory && - file.name.startsWith("browserbase-java") && + file.name.startsWith("stagehand-java") && file.listFiles()?.asSequence().orEmpty().any { it.name == "build.gradle.kts" } } .map { it.name } diff --git a/browserbase-java-client-okhttp/build.gradle.kts b/stagehand-java-client-okhttp/build.gradle.kts similarity index 76% rename from browserbase-java-client-okhttp/build.gradle.kts rename to stagehand-java-client-okhttp/build.gradle.kts index d5f5cb0..cb49933 100644 --- a/browserbase-java-client-okhttp/build.gradle.kts +++ b/stagehand-java-client-okhttp/build.gradle.kts @@ -1,10 +1,10 @@ plugins { - id("browserbase.kotlin") - id("browserbase.publish") + id("stagehand.kotlin") + id("stagehand.publish") } dependencies { - api(project(":browserbase-java-core")) + api(project(":stagehand-java-core")) implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") diff --git a/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt similarity index 96% rename from browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt rename to stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index 433919c..a624630 100644 --- a/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -8,7 +8,7 @@ import com.browserbase.api.core.http.HttpMethod import com.browserbase.api.core.http.HttpRequest import com.browserbase.api.core.http.HttpRequestBody import com.browserbase.api.core.http.HttpResponse -import com.browserbase.api.errors.BrowserbaseIoException +import com.browserbase.api.errors.StagehandIoException import java.io.IOException import java.io.InputStream import java.net.Proxy @@ -39,7 +39,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien return try { call.execute().toResponse() } catch (e: IOException) { - throw BrowserbaseIoException("Request failed", e) + throw StagehandIoException("Request failed", e) } finally { request.body?.close() } @@ -59,7 +59,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien } override fun onFailure(call: Call, e: IOException) { - future.completeExceptionally(BrowserbaseIoException("Request failed", e)) + future.completeExceptionally(StagehandIoException("Request failed", e)) } } ) @@ -84,7 +84,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien val clientBuilder = okHttpClient.newBuilder() val logLevel = - when (System.getenv("BROWSERBASE_LOG")?.lowercase()) { + when (System.getenv("STAGEHAND_LOG")?.lowercase()) { "info" -> HttpLoggingInterceptor.Level.BASIC "debug" -> HttpLoggingInterceptor.Level.BODY else -> null diff --git a/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt similarity index 95% rename from browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt rename to stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index dee001e..9114eb5 100644 --- a/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -2,8 +2,8 @@ package com.browserbase.api.client.okhttp -import com.browserbase.api.client.BrowserbaseClient -import com.browserbase.api.client.BrowserbaseClientImpl +import com.browserbase.api.client.StagehandClient +import com.browserbase.api.client.StagehandClientImpl import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.Sleeper import com.browserbase.api.core.Timeout @@ -22,14 +22,14 @@ import javax.net.ssl.X509TrustManager import kotlin.jvm.optionals.getOrNull /** - * A class that allows building an instance of [BrowserbaseClient] with [OkHttpClient] as the + * A class that allows building an instance of [StagehandClient] with [OkHttpClient] as the * underlying [HttpClient]. */ -class BrowserbaseOkHttpClient private constructor() { +class StagehandOkHttpClient private constructor() { companion object { - /** Returns a mutable builder for constructing an instance of [BrowserbaseClient]. */ + /** Returns a mutable builder for constructing an instance of [StagehandClient]. */ @JvmStatic fun builder() = Builder() /** @@ -37,10 +37,10 @@ class BrowserbaseOkHttpClient private constructor() { * * @see ClientOptions.Builder.fromEnv */ - @JvmStatic fun fromEnv(): BrowserbaseClient = builder().fromEnv().build() + @JvmStatic fun fromEnv(): StagehandClient = builder().fromEnv().build() } - /** A builder for [BrowserbaseOkHttpClient]. */ + /** A builder for [StagehandOkHttpClient]. */ class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() @@ -295,12 +295,12 @@ class BrowserbaseOkHttpClient private constructor() { fun fromEnv() = apply { clientOptions.fromEnv() } /** - * Returns an immutable instance of [BrowserbaseClient]. + * Returns an immutable instance of [StagehandClient]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): BrowserbaseClient = - BrowserbaseClientImpl( + fun build(): StagehandClient = + StagehandClientImpl( clientOptions .httpClient( OkHttpClient.builder() diff --git a/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt similarity index 95% rename from browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt rename to stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 924eb97..f16e2f8 100644 --- a/browserbase-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/BrowserbaseOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -2,8 +2,8 @@ package com.browserbase.api.client.okhttp -import com.browserbase.api.client.BrowserbaseClientAsync -import com.browserbase.api.client.BrowserbaseClientAsyncImpl +import com.browserbase.api.client.StagehandClientAsync +import com.browserbase.api.client.StagehandClientAsyncImpl import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.Sleeper import com.browserbase.api.core.Timeout @@ -22,14 +22,14 @@ import javax.net.ssl.X509TrustManager import kotlin.jvm.optionals.getOrNull /** - * A class that allows building an instance of [BrowserbaseClientAsync] with [OkHttpClient] as the + * A class that allows building an instance of [StagehandClientAsync] with [OkHttpClient] as the * underlying [HttpClient]. */ -class BrowserbaseOkHttpClientAsync private constructor() { +class StagehandOkHttpClientAsync private constructor() { companion object { - /** Returns a mutable builder for constructing an instance of [BrowserbaseClientAsync]. */ + /** Returns a mutable builder for constructing an instance of [StagehandClientAsync]. */ @JvmStatic fun builder() = Builder() /** @@ -37,10 +37,10 @@ class BrowserbaseOkHttpClientAsync private constructor() { * * @see ClientOptions.Builder.fromEnv */ - @JvmStatic fun fromEnv(): BrowserbaseClientAsync = builder().fromEnv().build() + @JvmStatic fun fromEnv(): StagehandClientAsync = builder().fromEnv().build() } - /** A builder for [BrowserbaseOkHttpClientAsync]. */ + /** A builder for [StagehandOkHttpClientAsync]. */ class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() @@ -295,12 +295,12 @@ class BrowserbaseOkHttpClientAsync private constructor() { fun fromEnv() = apply { clientOptions.fromEnv() } /** - * Returns an immutable instance of [BrowserbaseClientAsync]. + * Returns an immutable instance of [StagehandClientAsync]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): BrowserbaseClientAsync = - BrowserbaseClientAsyncImpl( + fun build(): StagehandClientAsync = + StagehandClientAsyncImpl( clientOptions .httpClient( OkHttpClient.builder() diff --git a/browserbase-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt b/stagehand-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt similarity index 100% rename from browserbase-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt rename to stagehand-java-client-okhttp/src/test/kotlin/com/browserbase/api/client/okhttp/OkHttpClientTest.kt diff --git a/browserbase-java-core/build.gradle.kts b/stagehand-java-core/build.gradle.kts similarity index 93% rename from browserbase-java-core/build.gradle.kts rename to stagehand-java-core/build.gradle.kts index ca10c97..38bcf47 100644 --- a/browserbase-java-core/build.gradle.kts +++ b/stagehand-java-core/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - id("browserbase.kotlin") - id("browserbase.publish") + id("stagehand.kotlin") + id("stagehand.publish") } configurations.all { @@ -29,7 +29,7 @@ dependencies { implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") testImplementation(kotlin("test")) - testImplementation(project(":browserbase-java-client-okhttp")) + testImplementation(project(":stagehand-java-client-okhttp")) testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") testImplementation("org.assertj:assertj-core:3.25.3") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClient.kt similarity index 85% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClient.kt index e77d3b1..a5c8c6c 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClient.kt @@ -7,7 +7,7 @@ import com.browserbase.api.services.blocking.SessionService import java.util.function.Consumer /** - * A client for interacting with the Browserbase REST API synchronously. You can also switch to + * A client for interacting with the Stagehand REST API synchronously. You can also switch to * asynchronous execution via the [async] method. * * This client performs best when you create a single instance and reuse it for all interactions @@ -20,7 +20,7 @@ import java.util.function.Consumer * if you are writing an application that needs to aggressively release unused resources, then you * may call [close]. */ -interface BrowserbaseClient { +interface StagehandClient { /** * Returns a version of this client that uses asynchronous execution. @@ -28,7 +28,7 @@ interface BrowserbaseClient { * The returned client shares its resources, like its connection pool and thread pools, with * this client. */ - fun async(): BrowserbaseClientAsync + fun async(): StagehandClientAsync /** * Returns a view of this service that provides access to raw HTTP responses for each method. @@ -40,7 +40,7 @@ interface BrowserbaseClient { * * The original service is not modified. */ - fun withOptions(modifier: Consumer): BrowserbaseClient + fun withOptions(modifier: Consumer): StagehandClient fun sessions(): SessionService @@ -57,7 +57,7 @@ interface BrowserbaseClient { */ fun close() - /** A view of [BrowserbaseClient] that provides access to raw HTTP responses for each method. */ + /** A view of [StagehandClient] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { /** @@ -65,9 +65,7 @@ interface BrowserbaseClient { * * The original service is not modified. */ - fun withOptions( - modifier: Consumer - ): BrowserbaseClient.WithRawResponse + fun withOptions(modifier: Consumer): StagehandClient.WithRawResponse fun sessions(): SessionService.WithRawResponse } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsync.kt similarity index 87% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsync.kt index 85a8cd5..27fd2a9 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsync.kt @@ -7,7 +7,7 @@ import com.browserbase.api.services.async.SessionServiceAsync import java.util.function.Consumer /** - * A client for interacting with the Browserbase REST API asynchronously. You can also switch to + * A client for interacting with the Stagehand REST API asynchronously. You can also switch to * synchronous execution via the [sync] method. * * This client performs best when you create a single instance and reuse it for all interactions @@ -20,7 +20,7 @@ import java.util.function.Consumer * if you are writing an application that needs to aggressively release unused resources, then you * may call [close]. */ -interface BrowserbaseClientAsync { +interface StagehandClientAsync { /** * Returns a version of this client that uses synchronous execution. @@ -28,7 +28,7 @@ interface BrowserbaseClientAsync { * The returned client shares its resources, like its connection pool and thread pools, with * this client. */ - fun sync(): BrowserbaseClient + fun sync(): StagehandClient /** * Returns a view of this service that provides access to raw HTTP responses for each method. @@ -40,7 +40,7 @@ interface BrowserbaseClientAsync { * * The original service is not modified. */ - fun withOptions(modifier: Consumer): BrowserbaseClientAsync + fun withOptions(modifier: Consumer): StagehandClientAsync fun sessions(): SessionServiceAsync @@ -58,8 +58,7 @@ interface BrowserbaseClientAsync { fun close() /** - * A view of [BrowserbaseClientAsync] that provides access to raw HTTP responses for each - * method. + * A view of [StagehandClientAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -70,7 +69,7 @@ interface BrowserbaseClientAsync { */ fun withOptions( modifier: Consumer - ): BrowserbaseClientAsync.WithRawResponse + ): StagehandClientAsync.WithRawResponse fun sessions(): SessionServiceAsync.WithRawResponse } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt similarity index 69% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt index 78e60db..2a0b813 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientAsyncImpl.kt @@ -8,8 +8,7 @@ import com.browserbase.api.services.async.SessionServiceAsync import com.browserbase.api.services.async.SessionServiceAsyncImpl import java.util.function.Consumer -class BrowserbaseClientAsyncImpl(private val clientOptions: ClientOptions) : - BrowserbaseClientAsync { +class StagehandClientAsyncImpl(private val clientOptions: ClientOptions) : StagehandClientAsync { private val clientOptionsWithUserAgent = if (clientOptions.headers.names().contains("User-Agent")) clientOptions @@ -20,9 +19,9 @@ class BrowserbaseClientAsyncImpl(private val clientOptions: ClientOptions) : .build() // Pass the original clientOptions so that this client sets its own User-Agent. - private val sync: BrowserbaseClient by lazy { BrowserbaseClientImpl(clientOptions) } + private val sync: StagehandClient by lazy { StagehandClientImpl(clientOptions) } - private val withRawResponse: BrowserbaseClientAsync.WithRawResponse by lazy { + private val withRawResponse: StagehandClientAsync.WithRawResponse by lazy { WithRawResponseImpl(clientOptions) } @@ -30,19 +29,19 @@ class BrowserbaseClientAsyncImpl(private val clientOptions: ClientOptions) : SessionServiceAsyncImpl(clientOptionsWithUserAgent) } - override fun sync(): BrowserbaseClient = sync + override fun sync(): StagehandClient = sync - override fun withRawResponse(): BrowserbaseClientAsync.WithRawResponse = withRawResponse + override fun withRawResponse(): StagehandClientAsync.WithRawResponse = withRawResponse - override fun withOptions(modifier: Consumer): BrowserbaseClientAsync = - BrowserbaseClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + override fun withOptions(modifier: Consumer): StagehandClientAsync = + StagehandClientAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) override fun sessions(): SessionServiceAsync = sessions override fun close() = clientOptions.close() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - BrowserbaseClientAsync.WithRawResponse { + StagehandClientAsync.WithRawResponse { private val sessions: SessionServiceAsync.WithRawResponse by lazy { SessionServiceAsyncImpl.WithRawResponseImpl(clientOptions) @@ -50,8 +49,8 @@ class BrowserbaseClientAsyncImpl(private val clientOptions: ClientOptions) : override fun withOptions( modifier: Consumer - ): BrowserbaseClientAsync.WithRawResponse = - BrowserbaseClientAsyncImpl.WithRawResponseImpl( + ): StagehandClientAsync.WithRawResponse = + StagehandClientAsyncImpl.WithRawResponseImpl( clientOptions.toBuilder().apply(modifier::accept).build() ) diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt similarity index 69% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt index 3df8a4f..8ea5907 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/client/BrowserbaseClientImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/client/StagehandClientImpl.kt @@ -8,7 +8,7 @@ import com.browserbase.api.services.blocking.SessionService import com.browserbase.api.services.blocking.SessionServiceImpl import java.util.function.Consumer -class BrowserbaseClientImpl(private val clientOptions: ClientOptions) : BrowserbaseClient { +class StagehandClientImpl(private val clientOptions: ClientOptions) : StagehandClient { private val clientOptionsWithUserAgent = if (clientOptions.headers.names().contains("User-Agent")) clientOptions @@ -19,27 +19,27 @@ class BrowserbaseClientImpl(private val clientOptions: ClientOptions) : Browserb .build() // Pass the original clientOptions so that this client sets its own User-Agent. - private val async: BrowserbaseClientAsync by lazy { BrowserbaseClientAsyncImpl(clientOptions) } + private val async: StagehandClientAsync by lazy { StagehandClientAsyncImpl(clientOptions) } - private val withRawResponse: BrowserbaseClient.WithRawResponse by lazy { + private val withRawResponse: StagehandClient.WithRawResponse by lazy { WithRawResponseImpl(clientOptions) } private val sessions: SessionService by lazy { SessionServiceImpl(clientOptionsWithUserAgent) } - override fun async(): BrowserbaseClientAsync = async + override fun async(): StagehandClientAsync = async - override fun withRawResponse(): BrowserbaseClient.WithRawResponse = withRawResponse + override fun withRawResponse(): StagehandClient.WithRawResponse = withRawResponse - override fun withOptions(modifier: Consumer): BrowserbaseClient = - BrowserbaseClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + override fun withOptions(modifier: Consumer): StagehandClient = + StagehandClientImpl(clientOptions.toBuilder().apply(modifier::accept).build()) override fun sessions(): SessionService = sessions override fun close() = clientOptions.close() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : - BrowserbaseClient.WithRawResponse { + StagehandClient.WithRawResponse { private val sessions: SessionService.WithRawResponse by lazy { SessionServiceImpl.WithRawResponseImpl(clientOptions) @@ -47,8 +47,8 @@ class BrowserbaseClientImpl(private val clientOptions: ClientOptions) : Browserb override fun withOptions( modifier: Consumer - ): BrowserbaseClient.WithRawResponse = - BrowserbaseClientImpl.WithRawResponseImpl( + ): StagehandClient.WithRawResponse = + StagehandClientImpl.WithRawResponseImpl( clientOptions.toBuilder().apply(modifier::accept).build() ) diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/BaseDeserializer.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/BaseSerializer.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Check.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 0032ba1..967f4dc 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -20,7 +20,7 @@ private constructor( /** * The HTTP client to use in the SDK. * - * Use the one published in `browserbase-java-client-okhttp` or implement your own. + * Use the one published in `stagehand-java-client-okhttp` or implement your own. * * This class takes ownership of the client and closes it when closed. */ @@ -177,7 +177,7 @@ private constructor( /** * The HTTP client to use in the SDK. * - * Use the one published in `browserbase-java-client-okhttp` or implement your own. + * Use the one published in `stagehand-java-client-okhttp` or implement your own. * * This class takes ownership of the client and closes it when closed. */ @@ -377,19 +377,20 @@ private constructor( * * See this table for the available options: * - * |Setter |System property |Environment variable |Required|Default value | - * |---------|-----------------------------|----------------------|--------|--------------------------------------------| - * |`apiKey` |`browserbase.stagehandApiKey`|`STAGEHAND_API_KEY` |true |- | - * |`baseUrl`|`browserbase.baseUrl` |`BROWSERBASE_BASE_URL`|true |`"https://api.stagehand.browserbase.com/v1"`| + * |Setter |System property |Environment variable|Required|Default value | + * |---------|-------------------|--------------------|--------|--------------------------------------------| + * |`apiKey` |`stagehand.apiKey` |`STAGEHAND_API_KEY` |true |- | + * |`baseUrl`|`stagehand.baseUrl`|`STAGEHAND_BASE_URL`|true |`"https://api.stagehand.browserbase.com/v1"`| * * System properties take precedence over environment variables. */ fun fromEnv() = apply { - (System.getProperty("browserbase.baseUrl") ?: System.getenv("BROWSERBASE_BASE_URL")) - ?.let { baseUrl(it) } - (System.getProperty("browserbase.stagehandApiKey") - ?: System.getenv("STAGEHAND_API_KEY")) - ?.let { apiKey(it) } + (System.getProperty("stagehand.baseUrl") ?: System.getenv("STAGEHAND_BASE_URL"))?.let { + baseUrl(it) + } + (System.getProperty("stagehand.apiKey") ?: System.getenv("STAGEHAND_API_KEY"))?.let { + apiKey(it) + } } /** diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/DefaultSleeper.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Params.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt similarity index 92% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt index 5c5bb35..12cba3f 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachable.kt @@ -2,7 +2,7 @@ package com.browserbase.api.core -import com.browserbase.api.errors.BrowserbaseException +import com.browserbase.api.errors.StagehandException import java.lang.reflect.InvocationTargetException /** @@ -46,7 +46,7 @@ private val closeWhenPhantomReachable: ((Any, () -> Unit) -> Unit)? by lazy { is Error -> throw cause } } - throw BrowserbaseException("Unexpected reflective invocation failure", e) + throw StagehandException("Unexpected reflective invocation failure", e) } } } catch (e: ReflectiveOperationException) { diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableExecutorService.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PhantomReachableSleeper.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/PrepareRequest.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt similarity index 88% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt index bbd1121..c14d552 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt @@ -2,7 +2,7 @@ package com.browserbase.api.core -import com.browserbase.api.client.BrowserbaseClient +import com.browserbase.api.client.StagehandClient fun getOsArch(): String { val osArch = System.getProperty("os.arch") @@ -37,6 +37,6 @@ fun getOsName(): String { fun getOsVersion(): String = System.getProperty("os.version", "unknown") fun getPackageVersion(): String = - BrowserbaseClient::class.java.`package`.implementationVersion ?: "unknown" + StagehandClient::class.java.`package`.implementationVersion ?: "unknown" fun getJavaVersion(): String = System.getProperty("java.version", "unknown") diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Sleeper.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Timeout.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt index c772038..c24f648 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt @@ -2,7 +2,7 @@ package com.browserbase.api.core -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import java.util.Collections import java.util.SortedMap import java.util.concurrent.CompletableFuture @@ -10,7 +10,7 @@ import java.util.concurrent.locks.Lock @JvmSynthetic internal fun T?.getOrThrow(name: String): T = - this ?: throw BrowserbaseInvalidDataException("`${name}` is not present") + this ?: throw StagehandInvalidDataException("`${name}` is not present") @JvmSynthetic internal fun List.toImmutable(): List = diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt index 3eb4836..db0102a 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt @@ -1,6 +1,6 @@ package com.browserbase.api.core -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JacksonAnnotationsInside import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonInclude @@ -108,7 +108,7 @@ sealed class JsonField { } fun asStringOrThrow(): String = - asString().orElseThrow { BrowserbaseInvalidDataException("Value is not a string") } + asString().orElseThrow { StagehandInvalidDataException("Value is not a string") } /** * Returns an [Optional] containing this field's list value, or an empty [Optional] if it @@ -171,9 +171,9 @@ sealed class JsonField { internal fun getRequired(name: String): T = when (this) { is KnownValue -> value - is JsonMissing -> throw BrowserbaseInvalidDataException("`$name` is not set") - is JsonNull -> throw BrowserbaseInvalidDataException("`$name` is null") - else -> throw BrowserbaseInvalidDataException("`$name` is invalid, received $this") + is JsonMissing -> throw StagehandInvalidDataException("`$name` is not set") + is JsonNull -> throw StagehandInvalidDataException("`$name` is null") + else -> throw StagehandInvalidDataException("`$name` is invalid, received $this") } @JvmSynthetic @@ -188,7 +188,7 @@ sealed class JsonField { is KnownValue -> Optional.of(value) is JsonMissing, is JsonNull -> Optional.empty() - else -> throw BrowserbaseInvalidDataException("`$name` is invalid, received $this") + else -> throw StagehandInvalidDataException("`$name` is invalid, received $this") } @JvmSynthetic diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/ErrorHandler.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt similarity index 80% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt index 994a55e..28b3462 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/JsonHandler.kt @@ -4,7 +4,7 @@ package com.browserbase.api.core.handlers import com.browserbase.api.core.http.HttpResponse import com.browserbase.api.core.http.HttpResponse.Handler -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef @@ -15,6 +15,6 @@ internal inline fun jsonHandler(jsonMapper: JsonMapper): Handler try { jsonMapper.readValue(response.body(), jacksonTypeRef()) } catch (e: Exception) { - throw BrowserbaseInvalidDataException("Error reading response", e) + throw StagehandInvalidDataException("Error reading response", e) } } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StringHandler.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/Headers.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpClient.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpMethod.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt index 05a1d50..499197e 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt @@ -5,7 +5,7 @@ package com.browserbase.api.core.http import com.browserbase.api.core.MultipartField -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.node.JsonNodeType @@ -97,7 +97,7 @@ internal fun multipartFormData( JsonNodeType.ARRAY, JsonNodeType.OBJECT, JsonNodeType.POJO -> - throw BrowserbaseInvalidDataException( + throw StagehandInvalidDataException( "Unexpected JsonNode type in array: ${node.nodeType}" ) } @@ -111,7 +111,7 @@ internal fun multipartFormData( } JsonNodeType.POJO, null -> - throw BrowserbaseInvalidDataException( + throw StagehandInvalidDataException( "Unexpected JsonNode type: ${node.nodeType}" ) } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBody.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponse.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpResponseFor.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingAsyncStreamResponse.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingHttpClient.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/PhantomReachableClosingStreamResponse.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/QueryParams.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt index 358057c..7e1a7aa 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt @@ -4,8 +4,8 @@ import com.browserbase.api.core.DefaultSleeper import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.Sleeper import com.browserbase.api.core.checkRequired -import com.browserbase.api.errors.BrowserbaseIoException -import com.browserbase.api.errors.BrowserbaseRetryableException +import com.browserbase.api.errors.StagehandIoException +import com.browserbase.api.errors.StagehandRetryableException import java.io.IOException import java.time.Clock import java.time.Duration @@ -182,8 +182,8 @@ private constructor( private fun shouldRetry(throwable: Throwable): Boolean = // Only retry known retryable exceptions, other exceptions are not intended to be retried. throwable is IOException || - throwable is BrowserbaseIoException || - throwable is BrowserbaseRetryableException + throwable is StagehandIoException || + throwable is StagehandRetryableException private fun getRetryBackoffDuration(retries: Int, response: HttpResponse?): Duration { // About the Retry-After header: diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt index 8281e6d..c56095d 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class BadRequestException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - BrowserbaseServiceException("400: $body", cause) { + StagehandServiceException("400: $body", cause) { override fun statusCode(): Int = 400 diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt index 3728e7d..c2b0d58 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt @@ -14,7 +14,7 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : BrowserbaseServiceException("$statusCode: $body", cause) { +) : StagehandServiceException("$statusCode: $body", cause) { override fun statusCode(): Int = statusCode diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt index 5fe3abd..b8dcbd2 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class NotFoundException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - BrowserbaseServiceException("404: $body", cause) { + StagehandServiceException("404: $body", cause) { override fun statusCode(): Int = 404 diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt index b161cb7..4c37a8a 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class PermissionDeniedException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - BrowserbaseServiceException("403: $body", cause) { + StagehandServiceException("403: $body", cause) { override fun statusCode(): Int = 403 diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt index cc270eb..b72ef4f 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class RateLimitException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - BrowserbaseServiceException("429: $body", cause) { + StagehandServiceException("429: $body", cause) { override fun statusCode(): Int = 429 diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandException.kt similarity index 82% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandException.kt index 2b49c25..214a6a8 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandException.kt @@ -1,5 +1,5 @@ package com.browserbase.api.errors -open class BrowserbaseException +open class StagehandException @JvmOverloads constructor(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause) diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt similarity index 58% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt index 28a9644..87fe2d4 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseInvalidDataException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt @@ -1,6 +1,5 @@ package com.browserbase.api.errors -class BrowserbaseInvalidDataException +class StagehandInvalidDataException @JvmOverloads -constructor(message: String? = null, cause: Throwable? = null) : - BrowserbaseException(message, cause) +constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandIoException.kt similarity index 61% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandIoException.kt index 6d8a71c..216ae66 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseIoException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandIoException.kt @@ -1,6 +1,5 @@ package com.browserbase.api.errors -class BrowserbaseIoException +class StagehandIoException @JvmOverloads -constructor(message: String? = null, cause: Throwable? = null) : - BrowserbaseException(message, cause) +constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandRetryableException.kt similarity index 85% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandRetryableException.kt index 1754ee9..18b8aca 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseRetryableException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandRetryableException.kt @@ -9,7 +9,6 @@ package com.browserbase.api.errors * @param message A descriptive error message * @param cause The underlying cause of this exception, if any */ -class BrowserbaseRetryableException +class StagehandRetryableException @JvmOverloads -constructor(message: String? = null, cause: Throwable? = null) : - BrowserbaseException(message, cause) +constructor(message: String? = null, cause: Throwable? = null) : StagehandException(message, cause) diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandServiceException.kt similarity index 80% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandServiceException.kt index bb5c849..71ce4fa 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/BrowserbaseServiceException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandServiceException.kt @@ -5,9 +5,9 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers -abstract class BrowserbaseServiceException +abstract class StagehandServiceException protected constructor(message: String, cause: Throwable? = null) : - BrowserbaseException(message, cause) { + StagehandException(message, cause) { abstract fun statusCode(): Int diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt index bdbd3ef..23ed90e 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class UnauthorizedException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - BrowserbaseServiceException("401: $body", cause) { + StagehandServiceException("401: $body", cause) { override fun statusCode(): Int = 401 diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt index 8b1a465..c375faa 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt @@ -14,7 +14,7 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : BrowserbaseServiceException("$statusCode: $body", cause) { +) : StagehandServiceException("$statusCode: $body", cause) { override fun statusCode(): Int = statusCode diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt similarity index 97% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt index 6fc0a4c..a162609 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt @@ -10,7 +10,7 @@ import kotlin.jvm.optionals.getOrNull class UnprocessableEntityException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - BrowserbaseServiceException("422: $body", cause) { + StagehandServiceException("422: $body", cause) { override fun statusCode(): Int = 422 diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt index fd113b6..d30a40b 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt @@ -9,7 +9,7 @@ import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkKnown import com.browserbase.api.core.checkRequired import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -48,7 +48,7 @@ private constructor( /** * Arguments for the method * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun arguments(): List = arguments.getRequired("arguments") @@ -56,7 +56,7 @@ private constructor( /** * Human-readable description of the action * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun description(): String = description.getRequired("description") @@ -64,7 +64,7 @@ private constructor( /** * Method to execute (e.g., "click", "fill") * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun method(): String = method.getRequired("method") @@ -72,7 +72,7 @@ private constructor( /** * CSS or XPath selector for the element * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun selector(): String = selector.getRequired("selector") @@ -80,7 +80,7 @@ private constructor( /** * CDP backend node ID * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") @@ -308,7 +308,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt similarity index 93% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 51355b2..e08ebfa 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -7,7 +7,7 @@ import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -38,7 +38,7 @@ private constructor( /** * API key for the model provider * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun apiKey(): Optional = apiKey.getOptional("apiKey") @@ -46,7 +46,7 @@ private constructor( /** * Custom base URL for API * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun baseUrl(): Optional = baseUrl.getOptional("baseURL") @@ -54,13 +54,13 @@ private constructor( /** * Model name * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun provider(): Optional = provider.getOptional("provider") @@ -219,7 +219,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -303,7 +303,7 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = @@ -311,7 +311,7 @@ private constructor( OPENAI -> Known.OPENAI ANTHROPIC -> Known.ANTHROPIC GOOGLE -> Known.GOOGLE - else -> throw BrowserbaseInvalidDataException("Unknown Provider: $value") + else -> throw StagehandInvalidDataException("Unknown Provider: $value") } /** @@ -320,12 +320,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -343,7 +343,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 37b2123..34cae33 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -16,7 +16,7 @@ import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -53,7 +53,7 @@ private constructor( /** * Natural language instruction * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun input(): Input = body.input() @@ -61,13 +61,13 @@ private constructor( /** * Frame ID to act on (optional) * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -372,7 +372,7 @@ private constructor( /** * Natural language instruction * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun input(): Input = input.getRequired("input") @@ -380,13 +380,13 @@ private constructor( /** * Frame ID to act on (optional) * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -551,7 +551,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -645,7 +645,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -709,10 +709,10 @@ private constructor( * version than the API, then the API may respond with new variants that the SDK is * unaware of. * - * @throws BrowserbaseInvalidDataException in the default implementation. + * @throws StagehandInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw BrowserbaseInvalidDataException("Unknown Input: $json") + throw StagehandInvalidDataException("Unknown Input: $json") } } @@ -782,7 +782,7 @@ private constructor( ) : this(model, timeout, variables, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -790,7 +790,7 @@ private constructor( /** * Timeout in milliseconds * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun timeout(): Optional = timeout.getOptional("timeout") @@ -798,7 +798,7 @@ private constructor( /** * Template variables for instruction * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun variables(): Optional = variables.getOptional("variables") @@ -940,7 +940,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -1030,7 +1030,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -1148,14 +1148,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -1164,12 +1164,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1187,7 +1187,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt index f07a16d..69dfcab 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -9,7 +9,7 @@ import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkKnown import com.browserbase.api.core.checkRequired import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -39,7 +39,7 @@ private constructor( /** * Actions that were executed * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun actions(): List = actions.getRequired("actions") @@ -47,7 +47,7 @@ private constructor( /** * Result message * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun message(): String = message.getRequired("message") @@ -55,7 +55,7 @@ private constructor( /** * Whether the action succeeded * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun success(): Boolean = success.getRequired("success") @@ -231,7 +231,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt index dd40544..feba7d7 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -6,7 +6,7 @@ import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -28,7 +28,7 @@ private constructor( ) : this(success, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun success(): Optional = success.getOptional("success") @@ -123,7 +123,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt index 570576f..d2c5c47 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt @@ -15,7 +15,7 @@ import com.browserbase.api.core.checkRequired import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -47,19 +47,19 @@ private constructor( fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun agentConfig(): AgentConfig = body.agentConfig() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun executeOptions(): ExecuteOptions = body.executeOptions() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() @@ -368,19 +368,19 @@ private constructor( ) : this(agentConfig, executeOptions, frameId, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun agentConfig(): AgentConfig = agentConfig.getRequired("agentConfig") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun executeOptions(): ExecuteOptions = executeOptions.getRequired("executeOptions") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") @@ -549,7 +549,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -612,25 +612,25 @@ private constructor( /** * Enable Computer Use Agent mode * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun cua(): Optional = cua.getOptional("cua") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun provider(): Optional = provider.getOptional("provider") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") @@ -801,7 +801,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -871,7 +871,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -935,10 +935,10 @@ private constructor( * version than the API, then the API may respond with new variants that the SDK is * unaware of. * - * @throws BrowserbaseInvalidDataException in the default implementation. + * @throws StagehandInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw BrowserbaseInvalidDataException("Unknown Model: $json") + throw StagehandInvalidDataException("Unknown Model: $json") } } @@ -1060,15 +1060,15 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and * don't want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a - * known member. + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. */ fun known(): Known = when (this) { OPENAI -> Known.OPENAI ANTHROPIC -> Known.ANTHROPIC GOOGLE -> Known.GOOGLE - else -> throw BrowserbaseInvalidDataException("Unknown Provider: $value") + else -> throw StagehandInvalidDataException("Unknown Provider: $value") } /** @@ -1077,12 +1077,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for * debugging and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have + * @throws StagehandInvalidDataException if this class instance's value does not have * the expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1100,7 +1100,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -1171,7 +1171,7 @@ private constructor( /** * Task for the agent to complete * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun instruction(): String = instruction.getRequired("instruction") @@ -1179,7 +1179,7 @@ private constructor( /** * Visually highlight the cursor during actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun highlightCursor(): Optional = highlightCursor.getOptional("highlightCursor") @@ -1187,7 +1187,7 @@ private constructor( /** * Maximum number of steps the agent can take * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") @@ -1357,7 +1357,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -1462,14 +1462,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -1478,12 +1478,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1501,7 +1501,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt index e126222..08afed9 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt @@ -8,7 +8,7 @@ import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkKnown import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -35,7 +35,7 @@ private constructor( /** * Final message from the agent * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun message(): Optional = message.getOptional("message") @@ -43,7 +43,7 @@ private constructor( /** * Steps taken by the agent * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun steps(): Optional> = steps.getOptional("steps") @@ -179,7 +179,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 652ea48..3833673 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -11,7 +11,7 @@ import com.browserbase.api.core.Params import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -41,7 +41,7 @@ private constructor( /** * Frame ID to extract from * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() @@ -49,13 +49,13 @@ private constructor( /** * Natural language instruction for extraction * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun instruction(): Optional = body.instruction() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -63,7 +63,7 @@ private constructor( /** * JSON Schema for structured output * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun schema(): Optional = body.schema() @@ -374,7 +374,7 @@ private constructor( /** * Frame ID to extract from * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") @@ -382,13 +382,13 @@ private constructor( /** * Natural language instruction for extraction * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun instruction(): Optional = instruction.getOptional("instruction") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -396,7 +396,7 @@ private constructor( /** * JSON Schema for structured output * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun schema(): Optional = schema.getOptional("schema") @@ -562,7 +562,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -621,7 +621,7 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -629,13 +629,13 @@ private constructor( /** * Extract only from elements matching this selector * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun selector(): Optional = selector.getOptional("selector") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun timeout(): Optional = timeout.getOptional("timeout") @@ -774,7 +774,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -883,7 +883,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -979,14 +979,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -995,12 +995,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1018,7 +1018,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt similarity index 96% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index 2a8b52c..322d090 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -11,7 +11,7 @@ import com.browserbase.api.core.JsonValue import com.browserbase.api.core.allMaxBy import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -87,7 +87,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -160,10 +160,10 @@ private constructor( * on an older version than the API, then the API may respond with new variants that the SDK * is unaware of. * - * @throws BrowserbaseInvalidDataException in the default implementation. + * @throws StagehandInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw BrowserbaseInvalidDataException("Unknown SessionExtractResponse: $json") + throw StagehandInvalidDataException("Unknown SessionExtractResponse: $json") } } @@ -230,7 +230,7 @@ private constructor( ) : this(extraction, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun extraction(): Optional = extraction.getOptional("extraction") @@ -327,7 +327,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -428,7 +428,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index f8dd95b..e57efd3 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -11,7 +11,7 @@ import com.browserbase.api.core.Params import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -38,19 +38,19 @@ private constructor( /** * URL to navigate to * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun url(): String = body.url() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -348,19 +348,19 @@ private constructor( /** * URL to navigate to * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun url(): String = url.getRequired("url") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -518,7 +518,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -573,7 +573,7 @@ private constructor( /** * When to consider navigation complete * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun waitUntil(): Optional = waitUntil.getOptional("waitUntil") @@ -671,7 +671,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -757,15 +757,15 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and * don't want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a - * known member. + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. */ fun known(): Known = when (this) { LOAD -> Known.LOAD DOMCONTENTLOADED -> Known.DOMCONTENTLOADED NETWORKIDLE -> Known.NETWORKIDLE - else -> throw BrowserbaseInvalidDataException("Unknown WaitUntil: $value") + else -> throw StagehandInvalidDataException("Unknown WaitUntil: $value") } /** @@ -774,12 +774,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for * debugging and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have + * @throws StagehandInvalidDataException if this class instance's value does not have * the expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -797,7 +797,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -907,14 +907,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -923,12 +923,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -946,7 +946,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt index 28a15c2..50422bd 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -6,7 +6,7 @@ import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -33,19 +33,19 @@ private constructor( ) : this(ok, status, url, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun ok(): Optional = ok.getOptional("ok") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun status(): Optional = status.getOptional("status") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun url(): Optional = url.getOptional("url") @@ -180,7 +180,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 802e3ea..0d67973 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -10,7 +10,7 @@ import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -40,7 +40,7 @@ private constructor( /** * Frame ID to observe * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun frameId(): Optional = body.frameId() @@ -48,13 +48,13 @@ private constructor( /** * Natural language instruction to filter actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun instruction(): Optional = body.instruction() /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun options(): Optional = body.options() @@ -344,7 +344,7 @@ private constructor( /** * Frame ID to observe * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun frameId(): Optional = frameId.getOptional("frameId") @@ -352,13 +352,13 @@ private constructor( /** * Natural language instruction to filter actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun instruction(): Optional = instruction.getOptional("instruction") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun options(): Optional = options.getOptional("options") @@ -502,7 +502,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -559,7 +559,7 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -567,13 +567,13 @@ private constructor( /** * Observe only elements matching this selector * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun selector(): Optional = selector.getOptional("selector") /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun timeout(): Optional = timeout.getOptional("timeout") @@ -712,7 +712,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -817,14 +817,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { TRUE -> Known.TRUE FALSE -> Known.FALSE - else -> throw BrowserbaseInvalidDataException("Unknown XStreamResponse: $value") + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") } /** @@ -833,12 +833,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -856,7 +856,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt similarity index 94% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 22ad279..011f19c 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -11,7 +11,7 @@ import com.browserbase.api.core.Params import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -35,7 +35,7 @@ private constructor( /** * Environment to run the browser in * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun env(): Env = body.env() @@ -43,7 +43,7 @@ private constructor( /** * API key for Browserbase (required when env=BROWSERBASE) * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun apiKey(): Optional = body.apiKey() @@ -51,7 +51,7 @@ private constructor( /** * Timeout in ms to wait for DOM to settle * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun domSettleTimeout(): Optional = body.domSettleTimeout() @@ -59,7 +59,7 @@ private constructor( /** * Options for local browser launch * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun localBrowserLaunchOptions(): Optional = @@ -68,7 +68,7 @@ private constructor( /** * AI model to use for actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun model(): Optional = body.model() @@ -76,7 +76,7 @@ private constructor( /** * Project ID for Browserbase (required when env=BROWSERBASE) * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun projectId(): Optional = body.projectId() @@ -84,7 +84,7 @@ private constructor( /** * Enable self-healing for failed actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun selfHeal(): Optional = body.selfHeal() @@ -92,7 +92,7 @@ private constructor( /** * Custom system prompt for AI actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun systemPrompt(): Optional = body.systemPrompt() @@ -100,7 +100,7 @@ private constructor( /** * Logging verbosity level * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if the + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun verbose(): Optional = body.verbose() @@ -532,7 +532,7 @@ private constructor( /** * Environment to run the browser in * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun env(): Env = env.getRequired("env") @@ -540,7 +540,7 @@ private constructor( /** * API key for Browserbase (required when env=BROWSERBASE) * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun apiKey(): Optional = apiKey.getOptional("apiKey") @@ -548,7 +548,7 @@ private constructor( /** * Timeout in ms to wait for DOM to settle * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun domSettleTimeout(): Optional = domSettleTimeout.getOptional("domSettleTimeout") @@ -556,7 +556,7 @@ private constructor( /** * Options for local browser launch * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun localBrowserLaunchOptions(): Optional = @@ -565,7 +565,7 @@ private constructor( /** * AI model to use for actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") @@ -573,7 +573,7 @@ private constructor( /** * Project ID for Browserbase (required when env=BROWSERBASE) * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun projectId(): Optional = projectId.getOptional("projectId") @@ -581,7 +581,7 @@ private constructor( /** * Enable self-healing for failed actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun selfHeal(): Optional = selfHeal.getOptional("selfHeal") @@ -589,7 +589,7 @@ private constructor( /** * Custom system prompt for AI actions * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") @@ -597,7 +597,7 @@ private constructor( /** * Logging verbosity level * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun verbose(): Optional = verbose.getOptional("verbose") @@ -914,7 +914,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -1039,14 +1039,14 @@ private constructor( * Use the [value] method instead if you're uncertain the value is always known and don't * want to throw for the unknown case. * - * @throws BrowserbaseInvalidDataException if this class instance's value is a not a known + * @throws StagehandInvalidDataException if this class instance's value is a not a known * member. */ fun known(): Known = when (this) { LOCAL -> Known.LOCAL BROWSERBASE -> Known.BROWSERBASE - else -> throw BrowserbaseInvalidDataException("Unknown Env: $value") + else -> throw StagehandInvalidDataException("Unknown Env: $value") } /** @@ -1055,12 +1055,12 @@ private constructor( * This differs from the [toString] method because that method is primarily for debugging * and generally doesn't throw. * - * @throws BrowserbaseInvalidDataException if this class instance's value does not have the + * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ fun asString(): String = _value().asString().orElseThrow { - BrowserbaseInvalidDataException("Value is not a String") + StagehandInvalidDataException("Value is not a String") } private var validated: Boolean = false @@ -1078,7 +1078,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } @@ -1119,7 +1119,7 @@ private constructor( ) : this(headless, mutableMapOf()) /** - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type (e.g. if + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun headless(): Optional = headless.getOptional("headless") @@ -1218,7 +1218,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt similarity index 95% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index 152fc44..2e71372 100644 --- a/browserbase-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -7,7 +7,7 @@ import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator @@ -32,7 +32,7 @@ private constructor( /** * Whether the session is ready to use * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun available(): Boolean = available.getRequired("available") @@ -40,7 +40,7 @@ private constructor( /** * Unique identifier for the session * - * @throws BrowserbaseInvalidDataException if the JSON field has an unexpected type or is + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun sessionId(): String = sessionId.getRequired("sessionId") @@ -179,7 +179,7 @@ private constructor( try { validate() true - } catch (e: BrowserbaseInvalidDataException) { + } catch (e: StagehandInvalidDataException) { false } diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt diff --git a/browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt similarity index 100% rename from browserbase-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt rename to stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt diff --git a/browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro b/stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro similarity index 100% rename from browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro rename to stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/PhantomReachableTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/UtilsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ValuesTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/AsyncStreamResponseTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HeadersTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/QueryParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt index 3275b09..b3fbe9b 100644 --- a/browserbase-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt @@ -3,7 +3,7 @@ package com.browserbase.api.core.http import com.browserbase.api.client.okhttp.OkHttpClient import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.Sleeper -import com.browserbase.api.errors.BrowserbaseRetryableException +import com.browserbase.api.errors.StagehandRetryableException import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest @@ -267,7 +267,7 @@ internal class RetryingHttpClientTest { ): HttpResponse { callCount++ if (callCount == 1) { - throw BrowserbaseRetryableException("Simulated retryable failure") + throw StagehandRetryableException("Simulated retryable failure") } return httpClient.execute(request, requestOptions) } @@ -280,7 +280,7 @@ internal class RetryingHttpClientTest { if (callCount == 1) { val future = CompletableFuture() future.completeExceptionally( - BrowserbaseRetryableException("Simulated retryable failure") + StagehandRetryableException("Simulated retryable failure") ) return future } diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt similarity index 95% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt index c11f3f5..2bd928d 100644 --- a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt @@ -4,7 +4,7 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper -import com.browserbase.api.errors.BrowserbaseInvalidDataException +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -88,7 +88,7 @@ internal class SessionExtractResponseTest { val sessionExtractResponse = jsonMapper().convertValue(testCase.value, jacksonTypeRef()) - val e = assertThrows { sessionExtractResponse.validate() } + val e = assertThrows { sessionExtractResponse.validate() } assertThat(e).hasMessageStartingWith("Unknown ") } } diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt similarity index 100% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt similarity index 98% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index d9c176d..1a59424 100644 --- a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -2,17 +2,17 @@ package com.browserbase.api.services -import com.browserbase.api.client.BrowserbaseClient -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.client.StagehandClient +import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers import com.browserbase.api.core.jsonMapper import com.browserbase.api.errors.BadRequestException -import com.browserbase.api.errors.BrowserbaseException import com.browserbase.api.errors.InternalServerException import com.browserbase.api.errors.NotFoundException import com.browserbase.api.errors.PermissionDeniedException import com.browserbase.api.errors.RateLimitException +import com.browserbase.api.errors.StagehandException import com.browserbase.api.errors.UnauthorizedException import com.browserbase.api.errors.UnexpectedStatusCodeException import com.browserbase.api.errors.UnprocessableEntityException @@ -47,12 +47,12 @@ internal class ErrorHandlingTest { private const val NOT_JSON: String = "Not JSON" } - private lateinit var client: BrowserbaseClient + private lateinit var client: StagehandClient @BeforeEach fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(wmRuntimeInfo.httpBaseUrl) .apiKey("My API Key") .build() @@ -643,7 +643,7 @@ internal class ErrorHandlingTest { ) val e = - assertThrows { + assertThrows { sessionService.start( SessionStartParams.builder() .env(SessionStartParams.Env.LOCAL) diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt similarity index 92% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 1fdec72..d02d7c6 100644 --- a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -2,8 +2,8 @@ package com.browserbase.api.services -import com.browserbase.api.client.BrowserbaseClient -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.client.StagehandClient +import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl @@ -25,12 +25,12 @@ import org.junit.jupiter.api.parallel.ResourceLock @ResourceLock("https://github.com/wiremock/wiremock/issues/169") internal class ServiceParamsTest { - private lateinit var client: BrowserbaseClient + private lateinit var client: StagehandClient @BeforeEach fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(wmRuntimeInfo.httpBaseUrl) .apiKey("My API Key") .build() diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt similarity index 95% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 64260cb..12cedb1 100644 --- a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -3,7 +3,7 @@ package com.browserbase.api.services.async import com.browserbase.api.TestServerExtension -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClientAsync +import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.ModelConfig import com.browserbase.api.models.sessions.SessionActParams @@ -24,7 +24,7 @@ internal class SessionServiceAsyncTest { @Test fun act() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -66,7 +66,7 @@ internal class SessionServiceAsyncTest { @Test fun end() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -82,7 +82,7 @@ internal class SessionServiceAsyncTest { @Test fun executeAgent() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -120,7 +120,7 @@ internal class SessionServiceAsyncTest { @Test fun extract() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -163,7 +163,7 @@ internal class SessionServiceAsyncTest { @Test fun navigate() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -193,7 +193,7 @@ internal class SessionServiceAsyncTest { @Test fun observe() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -231,7 +231,7 @@ internal class SessionServiceAsyncTest { @Test fun start() { val client = - BrowserbaseOkHttpClientAsync.builder() + StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() diff --git a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt similarity index 95% rename from browserbase-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt rename to stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index cbd77b3..bc2c422 100644 --- a/browserbase-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -3,7 +3,7 @@ package com.browserbase.api.services.blocking import com.browserbase.api.TestServerExtension -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.ModelConfig import com.browserbase.api.models.sessions.SessionActParams @@ -24,7 +24,7 @@ internal class SessionServiceTest { @Test fun act() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -65,7 +65,7 @@ internal class SessionServiceTest { @Test fun end() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -80,7 +80,7 @@ internal class SessionServiceTest { @Test fun executeAgent() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -117,7 +117,7 @@ internal class SessionServiceTest { @Test fun extract() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -159,7 +159,7 @@ internal class SessionServiceTest { @Test fun navigate() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -188,7 +188,7 @@ internal class SessionServiceTest { @Test fun observe() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() @@ -225,7 +225,7 @@ internal class SessionServiceTest { @Test fun start() { val client = - BrowserbaseOkHttpClient.builder() + StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) .apiKey("My API Key") .build() diff --git a/browserbase-java-proguard-test/build.gradle.kts b/stagehand-java-proguard-test/build.gradle.kts similarity index 90% rename from browserbase-java-proguard-test/build.gradle.kts rename to stagehand-java-proguard-test/build.gradle.kts index 4226829..9641bb2 100644 --- a/browserbase-java-proguard-test/build.gradle.kts +++ b/stagehand-java-proguard-test/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("browserbase.kotlin") + id("stagehand.kotlin") id("com.gradleup.shadow") version "8.3.8" } @@ -15,7 +15,7 @@ buildscript { } dependencies { - testImplementation(project(":browserbase-java")) + testImplementation(project(":stagehand-java")) testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") @@ -51,7 +51,7 @@ val proguardJar by tasks.registering(proguard.gradle.ProGuardTask::class) { } configuration("./test.pro") - configuration("../browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro") + configuration("../stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro") } val testProGuard by tasks.registering(JavaExec::class) { @@ -78,7 +78,7 @@ val r8Jar by tasks.registering(JavaExec::class) { "--output", r8JarPath, "--lib", System.getProperty("java.home"), "--pg-conf", "./test.pro", - "--pg-conf", "../browserbase-java-core/src/main/resources/META-INF/proguard/browserbase-java-core.pro", + "--pg-conf", "../stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro", "--pg-map-output", "${layout.buildDirectory.get()}/r8-mapping.txt", tasks.shadowJar.get().archiveFile.get().asFile.absolutePath, ) diff --git a/browserbase-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt similarity index 93% rename from browserbase-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt rename to stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 73126fc..2ac121d 100644 --- a/browserbase-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -2,7 +2,7 @@ package com.browserbase.api.proguard -import com.browserbase.api.client.okhttp.BrowserbaseOkHttpClient +import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.jsonMapper import com.browserbase.api.models.sessions.Action import com.browserbase.api.models.sessions.SessionExtractResponse @@ -38,14 +38,14 @@ internal class ProGuardCompatibilityTest { @Test fun proguardRules() { val rulesFile = - javaClass.classLoader.getResourceAsStream("META-INF/proguard/browserbase-java-core.pro") + javaClass.classLoader.getResourceAsStream("META-INF/proguard/stagehand-java-core.pro") assertThat(rulesFile).isNotNull() } @Test fun client() { - val client = BrowserbaseOkHttpClient.builder().apiKey("My API Key").build() + val client = StagehandOkHttpClient.builder().apiKey("My API Key").build() assertThat(client).isNotNull() assertThat(client.sessions()).isNotNull() diff --git a/browserbase-java-proguard-test/test.pro b/stagehand-java-proguard-test/test.pro similarity index 100% rename from browserbase-java-proguard-test/test.pro rename to stagehand-java-proguard-test/test.pro diff --git a/browserbase-java/build.gradle.kts b/stagehand-java/build.gradle.kts similarity index 85% rename from browserbase-java/build.gradle.kts rename to stagehand-java/build.gradle.kts index 86b7f8c..6d32486 100644 --- a/browserbase-java/build.gradle.kts +++ b/stagehand-java/build.gradle.kts @@ -1,10 +1,10 @@ plugins { - id("browserbase.kotlin") - id("browserbase.publish") + id("stagehand.kotlin") + id("stagehand.publish") } dependencies { - api(project(":browserbase-java-client-okhttp")) + api(project(":stagehand-java-client-okhttp")) } // Redefine `dokkaJavadoc` to: From 8687b2ccd9afea12fe04d6a6b0bd782c798b7dab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:21:27 +0000 Subject: [PATCH 013/164] feat(api): manual updates --- .stats.yml | 6 +++--- buildSrc/src/main/kotlin/stagehand.publish.gradle.kts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8741890..c128648 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-0c12f985340be2a9287e8e01ff8733f7f2d02e019149d1ae95f1a8f8798c6690.yml -openapi_spec_hash: efb79934e1dc63763dd4e8493b825273 -config_hash: 1de7cb9bd4dc46fe3e20b637bc534908 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-cacb08bfd03b2d325b80318fc3f12bc7da16f229c21e9bd86050fff4ef7c67f7.yml +openapi_spec_hash: 21dc2123dc758a738591bf914410041a +config_hash: bb7561632c1f66c2b9efca06f438f904 diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index 9f64944..97e7bfb 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -9,8 +9,8 @@ configure { from(components["java"]) pom { - name.set("Stagehand P2P Server API") - description.set("HTTP API for remote Stagehand browser automation. This API allows clients to\nconnect to a Stagehand server and execute browser automation tasks remotely.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.") + name.set("Stagehand API") + description.set("Stagehand SDK for AI browser automation. This API allows clients to execute\nbrowser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.") url.set("https://docs.stagehand.dev") licenses { From 40e2ed90e0fad23bbcd9c03ce6d6e6be92cd8d4c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:28:09 +0000 Subject: [PATCH 014/164] feat(api): manual updates --- .stats.yml | 4 ++-- buildSrc/src/main/kotlin/stagehand.publish.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index c128648..a06fa53 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-cacb08bfd03b2d325b80318fc3f12bc7da16f229c21e9bd86050fff4ef7c67f7.yml -openapi_spec_hash: 21dc2123dc758a738591bf914410041a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-09064f4021f94fb1b1bd86ce496d998318276b61bbc24de4728ecdb5763847ef.yml +openapi_spec_hash: 911d0631010b372890f98545a038cfb5 config_hash: bb7561632c1f66c2b9efca06f438f904 diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index 97e7bfb..7b0ce3f 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -10,7 +10,7 @@ configure { pom { name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation. This API allows clients to execute\nbrowser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") url.set("https://docs.stagehand.dev") licenses { From b13570e610f7883e8e5db17b31af9921ec30c898 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:39:07 +0000 Subject: [PATCH 015/164] feat(api): manual updates --- .stats.yml | 6 +- README.md | 83 +-- .../api/models/sessions/SessionStartParams.kt | 621 ++++-------------- .../models/sessions/SessionStartParamsTest.kt | 32 +- .../api/services/ErrorHandlingTest.kt | 170 +---- .../api/services/ServiceParamsTest.kt | 54 +- .../services/async/SessionServiceAsyncTest.kt | 10 +- .../services/blocking/SessionServiceTest.kt | 10 +- 8 files changed, 261 insertions(+), 725 deletions(-) diff --git a/.stats.yml b/.stats.yml index a06fa53..4664845 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-09064f4021f94fb1b1bd86ce496d998318276b61bbc24de4728ecdb5763847ef.yml -openapi_spec_hash: 911d0631010b372890f98545a038cfb5 -config_hash: bb7561632c1f66c2b9efca06f438f904 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-6a22863a7da4fa45f904657a4cb8fc1a28e236925f03dc94fca25fd8271ca6db.yml +openapi_spec_hash: d5c6108942ad79f39ea4ff1bee9b7996 +config_hash: 2f1ec44e7e07906e07bdc6e075763da9 diff --git a/README.md b/README.md index 8453788..a71554c 100644 --- a/README.md +++ b/README.md @@ -48,17 +48,18 @@ This library requires Java 8 or later. ```java import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); -SessionStartParams params = SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) +SessionActParams params = SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .input("click the first link on the page") .build(); -SessionStartResponse response = client.sessions().start(params); +SessionActResponse response = client.sessions().act(params); ``` ## Client configuration @@ -131,7 +132,7 @@ The `withOptions()` method does not affect the original client or service. To send a request to the Stagehand API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. -For example, `client.sessions().start(...)` should be called with an instance of `SessionStartParams`, and it will return an instance of `SessionStartResponse`. +For example, `client.sessions().act(...)` should be called with an instance of `SessionActParams`, and it will return an instance of `SessionActResponse`. ## Immutability @@ -148,18 +149,19 @@ The default client is synchronous. To switch to asynchronous execution, call the ```java import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; import java.util.concurrent.CompletableFuture; // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); -SessionStartParams params = SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) +SessionActParams params = SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .input("click the first link on the page") .build(); -CompletableFuture response = client.async().sessions().start(params); +CompletableFuture response = client.async().sessions().act(params); ``` Or create an asynchronous client from the beginning: @@ -167,18 +169,19 @@ Or create an asynchronous client from the beginning: ```java import com.browserbase.api.client.StagehandClientAsync; import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; import java.util.concurrent.CompletableFuture; // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); -SessionStartParams params = SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) +SessionActParams params = SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .input("click the first link on the page") .build(); -CompletableFuture response = client.sessions().start(params); +CompletableFuture response = client.sessions().act(params); ``` The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. @@ -196,7 +199,8 @@ import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .build(); HttpResponseFor response = client.sessions().withRawResponse().start(params); @@ -427,9 +431,9 @@ To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQu ```java import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; -SessionStartParams params = SessionStartParams.builder() +SessionActParams params = SessionActParams.builder() .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) @@ -442,10 +446,10 @@ To set undocumented parameters on _nested_ headers, query params, or body classe ```java import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; -SessionStartParams params = SessionStartParams.builder() - .localBrowserLaunchOptions(SessionStartParams.LocalBrowserLaunchOptions.builder() +SessionActParams params = SessionActParams.builder() + .options(SessionActParams.Options.builder() .putAdditionalProperty("secretProperty", JsonValue.from("42")) .build()) .build(); @@ -457,10 +461,10 @@ To set a documented parameter or property to an undocumented or not yet supporte ```java import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; -SessionStartParams params = SessionStartParams.builder() - .env(JsonValue.from(42)) +SessionActParams params = SessionActParams.builder() + .input(JsonValue.from(42)) .build(); ``` @@ -509,10 +513,11 @@ To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehan ```java import com.browserbase.api.core.JsonMissing; -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; -SessionStartParams params = SessionStartParams.builder() - .env(JsonMissing.of()) +SessionActParams params = SessionActParams.builder() + .input("click the sign in button") + .sessionId(JsonMissing.of()) .build(); ``` @@ -524,7 +529,7 @@ To access undocumented response properties, call the `_additionalProperties()` m import com.browserbase.api.core.JsonValue; import java.util.Map; -Map additionalProperties = client.sessions().start(params)._additionalProperties(); +Map additionalProperties = client.sessions().act(params)._additionalProperties(); JsonValue secretPropertyValue = additionalProperties.get("secretProperty"); String result = secretPropertyValue.accept(new JsonValue.Visitor<>() { @@ -552,22 +557,22 @@ To access a property's raw JSON value, which may be undocumented, call its `_` p ```java import com.browserbase.api.core.JsonField; -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; import java.util.Optional; -JsonField env = client.sessions().start(params)._env(); +JsonField input = client.sessions().act(params)._input(); -if (env.isMissing()) { +if (input.isMissing()) { // The property is absent from the JSON response -} else if (env.isNull()) { +} else if (input.isNull()) { // The property was set to literal null } else { // Check if value was provided as a string // Other methods include `asNumber()`, `asBoolean()`, etc. - Optional jsonString = env.asString(); + Optional jsonString = input.asString(); // Try to deserialize into a custom type - MyClass myObject = env.asUnknown().orElseThrow().convert(MyClass.class); + MyClass myObject = input.asUnknown().orElseThrow().convert(MyClass.class); } ``` @@ -580,17 +585,17 @@ By default, the SDK will not throw an exception in this case. It will throw [`St If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: ```java -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActResponse; -SessionStartResponse response = client.sessions().start(params).validate(); +SessionActResponse response = client.sessions().act(params).validate(); ``` Or configure the method call to validate the response using the `responseValidation` method: ```java -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActResponse; -SessionStartResponse response = client.sessions().start( +SessionActResponse response = client.sessions().act( params, RequestOptions.builder().responseValidation(true).build() ); ``` diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 011f19c..cda3e99 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -19,7 +18,6 @@ import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects import java.util.Optional -import kotlin.jvm.optionals.getOrNull /** * Initializes a new Stagehand session with a browser instance. Returns a session ID that must be @@ -33,20 +31,20 @@ private constructor( ) : Params { /** - * Environment to run the browser in + * API key for Browserbase Cloud * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun env(): Env = body.env() + fun browserbaseApiKey(): String = body.browserbaseApiKey() /** - * API key for Browserbase (required when env=BROWSERBASE) + * Project ID for Browserbase * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun apiKey(): Optional = body.apiKey() + fun browserbaseProjectId(): String = body.browserbaseProjectId() /** * Timeout in ms to wait for DOM to settle @@ -57,30 +55,13 @@ private constructor( fun domSettleTimeout(): Optional = body.domSettleTimeout() /** - * Options for local browser launch - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun localBrowserLaunchOptions(): Optional = - body.localBrowserLaunchOptions() - - /** - * AI model to use for actions + * AI model to use for actions (must be prefixed with provider/) * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ fun model(): Optional = body.model() - /** - * Project ID for Browserbase (required when env=BROWSERBASE) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun projectId(): Optional = body.projectId() - /** * Enable self-healing for failed actions * @@ -106,18 +87,20 @@ private constructor( fun verbose(): Optional = body.verbose() /** - * Returns the raw JSON value of [env]. + * Returns the raw JSON value of [browserbaseApiKey]. * - * Unlike [env], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [browserbaseApiKey], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun _env(): JsonField = body._env() + fun _browserbaseApiKey(): JsonField = body._browserbaseApiKey() /** - * Returns the raw JSON value of [apiKey]. + * Returns the raw JSON value of [browserbaseProjectId]. * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [browserbaseProjectId], this method doesn't throw if the JSON field has an unexpected + * type. */ - fun _apiKey(): JsonField = body._apiKey() + fun _browserbaseProjectId(): JsonField = body._browserbaseProjectId() /** * Returns the raw JSON value of [domSettleTimeout]. @@ -127,15 +110,6 @@ private constructor( */ fun _domSettleTimeout(): JsonField = body._domSettleTimeout() - /** - * Returns the raw JSON value of [localBrowserLaunchOptions]. - * - * Unlike [localBrowserLaunchOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - fun _localBrowserLaunchOptions(): JsonField = - body._localBrowserLaunchOptions() - /** * Returns the raw JSON value of [model]. * @@ -143,13 +117,6 @@ private constructor( */ fun _model(): JsonField = body._model() - /** - * Returns the raw JSON value of [projectId]. - * - * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _projectId(): JsonField = body._projectId() - /** * Returns the raw JSON value of [selfHeal]. * @@ -188,7 +155,8 @@ private constructor( * * The following fields are required: * ```java - * .env() + * .browserbaseApiKey() + * .browserbaseProjectId() * ``` */ @JvmStatic fun builder() = Builder() @@ -213,36 +181,46 @@ private constructor( * * This is generally only useful if you are already constructing the body separately. * Otherwise, it's more convenient to use the top-level setters instead: - * - [env] - * - [apiKey] + * - [browserbaseApiKey] + * - [browserbaseProjectId] * - [domSettleTimeout] - * - [localBrowserLaunchOptions] * - [model] + * - [selfHeal] * - etc. */ fun body(body: Body) = apply { this.body = body.toBuilder() } - /** Environment to run the browser in */ - fun env(env: Env) = apply { body.env(env) } + /** API key for Browserbase Cloud */ + fun browserbaseApiKey(browserbaseApiKey: String) = apply { + body.browserbaseApiKey(browserbaseApiKey) + } /** - * Sets [Builder.env] to an arbitrary JSON value. + * Sets [Builder.browserbaseApiKey] to an arbitrary JSON value. * - * You should usually call [Builder.env] with a well-typed [Env] value instead. This method - * is primarily for setting the field to an undocumented or not yet supported value. + * You should usually call [Builder.browserbaseApiKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun env(env: JsonField) = apply { body.env(env) } + fun browserbaseApiKey(browserbaseApiKey: JsonField) = apply { + body.browserbaseApiKey(browserbaseApiKey) + } - /** API key for Browserbase (required when env=BROWSERBASE) */ - fun apiKey(apiKey: String) = apply { body.apiKey(apiKey) } + /** Project ID for Browserbase */ + fun browserbaseProjectId(browserbaseProjectId: String) = apply { + body.browserbaseProjectId(browserbaseProjectId) + } /** - * Sets [Builder.apiKey] to an arbitrary JSON value. + * Sets [Builder.browserbaseProjectId] to an arbitrary JSON value. * - * You should usually call [Builder.apiKey] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * You should usually call [Builder.browserbaseProjectId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun apiKey(apiKey: JsonField) = apply { body.apiKey(apiKey) } + fun browserbaseProjectId(browserbaseProjectId: JsonField) = apply { + body.browserbaseProjectId(browserbaseProjectId) + } /** Timeout in ms to wait for DOM to settle */ fun domSettleTimeout(domSettleTimeout: Long) = apply { @@ -260,24 +238,7 @@ private constructor( body.domSettleTimeout(domSettleTimeout) } - /** Options for local browser launch */ - fun localBrowserLaunchOptions(localBrowserLaunchOptions: LocalBrowserLaunchOptions) = - apply { - body.localBrowserLaunchOptions(localBrowserLaunchOptions) - } - - /** - * Sets [Builder.localBrowserLaunchOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.localBrowserLaunchOptions] with a well-typed - * [LocalBrowserLaunchOptions] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun localBrowserLaunchOptions( - localBrowserLaunchOptions: JsonField - ) = apply { body.localBrowserLaunchOptions(localBrowserLaunchOptions) } - - /** AI model to use for actions */ + /** AI model to use for actions (must be prefixed with provider/) */ fun model(model: String) = apply { body.model(model) } /** @@ -288,18 +249,6 @@ private constructor( */ fun model(model: JsonField) = apply { body.model(model) } - /** Project ID for Browserbase (required when env=BROWSERBASE) */ - fun projectId(projectId: String) = apply { body.projectId(projectId) } - - /** - * Sets [Builder.projectId] to an arbitrary JSON value. - * - * You should usually call [Builder.projectId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun projectId(projectId: JsonField) = apply { body.projectId(projectId) } - /** Enable self-healing for failed actions */ fun selfHeal(selfHeal: Boolean) = apply { body.selfHeal(selfHeal) } @@ -461,7 +410,8 @@ private constructor( * * The following fields are required: * ```java - * .env() + * .browserbaseApiKey() + * .browserbaseProjectId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -483,12 +433,10 @@ private constructor( class Body @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val env: JsonField, - private val apiKey: JsonField, + private val browserbaseApiKey: JsonField, + private val browserbaseProjectId: JsonField, private val domSettleTimeout: JsonField, - private val localBrowserLaunchOptions: JsonField, private val model: JsonField, - private val projectId: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, private val verbose: JsonField, @@ -497,18 +445,16 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("env") @ExcludeMissing env: JsonField = JsonMissing.of(), - @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), + @JsonProperty("BROWSERBASE_API_KEY") + @ExcludeMissing + browserbaseApiKey: JsonField = JsonMissing.of(), + @JsonProperty("BROWSERBASE_PROJECT_ID") + @ExcludeMissing + browserbaseProjectId: JsonField = JsonMissing.of(), @JsonProperty("domSettleTimeout") @ExcludeMissing domSettleTimeout: JsonField = JsonMissing.of(), - @JsonProperty("localBrowserLaunchOptions") - @ExcludeMissing - localBrowserLaunchOptions: JsonField = JsonMissing.of(), @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("projectId") - @ExcludeMissing - projectId: JsonField = JsonMissing.of(), @JsonProperty("selfHeal") @ExcludeMissing selfHeal: JsonField = JsonMissing.of(), @@ -517,12 +463,10 @@ private constructor( systemPrompt: JsonField = JsonMissing.of(), @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), ) : this( - env, - apiKey, + browserbaseApiKey, + browserbaseProjectId, domSettleTimeout, - localBrowserLaunchOptions, model, - projectId, selfHeal, systemPrompt, verbose, @@ -530,20 +474,21 @@ private constructor( ) /** - * Environment to run the browser in + * API key for Browserbase Cloud * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun env(): Env = env.getRequired("env") + fun browserbaseApiKey(): String = browserbaseApiKey.getRequired("BROWSERBASE_API_KEY") /** - * API key for Browserbase (required when env=BROWSERBASE) + * Project ID for Browserbase * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun apiKey(): Optional = apiKey.getOptional("apiKey") + fun browserbaseProjectId(): String = + browserbaseProjectId.getRequired("BROWSERBASE_PROJECT_ID") /** * Timeout in ms to wait for DOM to settle @@ -554,30 +499,13 @@ private constructor( fun domSettleTimeout(): Optional = domSettleTimeout.getOptional("domSettleTimeout") /** - * Options for local browser launch - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun localBrowserLaunchOptions(): Optional = - localBrowserLaunchOptions.getOptional("localBrowserLaunchOptions") - - /** - * AI model to use for actions + * AI model to use for actions (must be prefixed with provider/) * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun model(): Optional = model.getOptional("model") - /** - * Project ID for Browserbase (required when env=BROWSERBASE) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun projectId(): Optional = projectId.getOptional("projectId") - /** * Enable self-healing for failed actions * @@ -603,18 +531,24 @@ private constructor( fun verbose(): Optional = verbose.getOptional("verbose") /** - * Returns the raw JSON value of [env]. + * Returns the raw JSON value of [browserbaseApiKey]. * - * Unlike [env], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [browserbaseApiKey], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("env") @ExcludeMissing fun _env(): JsonField = env + @JsonProperty("BROWSERBASE_API_KEY") + @ExcludeMissing + fun _browserbaseApiKey(): JsonField = browserbaseApiKey /** - * Returns the raw JSON value of [apiKey]. + * Returns the raw JSON value of [browserbaseProjectId]. * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [browserbaseProjectId], this method doesn't throw if the JSON field has an + * unexpected type. */ - @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + @JsonProperty("BROWSERBASE_PROJECT_ID") + @ExcludeMissing + fun _browserbaseProjectId(): JsonField = browserbaseProjectId /** * Returns the raw JSON value of [domSettleTimeout]. @@ -626,17 +560,6 @@ private constructor( @ExcludeMissing fun _domSettleTimeout(): JsonField = domSettleTimeout - /** - * Returns the raw JSON value of [localBrowserLaunchOptions]. - * - * Unlike [localBrowserLaunchOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("localBrowserLaunchOptions") - @ExcludeMissing - fun _localBrowserLaunchOptions(): JsonField = - localBrowserLaunchOptions - /** * Returns the raw JSON value of [model]. * @@ -644,13 +567,6 @@ private constructor( */ @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - /** - * Returns the raw JSON value of [projectId]. - * - * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("projectId") @ExcludeMissing fun _projectId(): JsonField = projectId - /** * Returns the raw JSON value of [selfHeal]. * @@ -694,7 +610,8 @@ private constructor( * * The following fields are required: * ```java - * .env() + * .browserbaseApiKey() + * .browserbaseProjectId() * ``` */ @JvmStatic fun builder() = Builder() @@ -703,13 +620,10 @@ private constructor( /** A builder for [Body]. */ class Builder internal constructor() { - private var env: JsonField? = null - private var apiKey: JsonField = JsonMissing.of() + private var browserbaseApiKey: JsonField? = null + private var browserbaseProjectId: JsonField? = null private var domSettleTimeout: JsonField = JsonMissing.of() - private var localBrowserLaunchOptions: JsonField = - JsonMissing.of() private var model: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() private var verbose: JsonField = JsonMissing.of() @@ -717,41 +631,45 @@ private constructor( @JvmSynthetic internal fun from(body: Body) = apply { - env = body.env - apiKey = body.apiKey + browserbaseApiKey = body.browserbaseApiKey + browserbaseProjectId = body.browserbaseProjectId domSettleTimeout = body.domSettleTimeout - localBrowserLaunchOptions = body.localBrowserLaunchOptions model = body.model - projectId = body.projectId selfHeal = body.selfHeal systemPrompt = body.systemPrompt verbose = body.verbose additionalProperties = body.additionalProperties.toMutableMap() } - /** Environment to run the browser in */ - fun env(env: Env) = env(JsonField.of(env)) + /** API key for Browserbase Cloud */ + fun browserbaseApiKey(browserbaseApiKey: String) = + browserbaseApiKey(JsonField.of(browserbaseApiKey)) /** - * Sets [Builder.env] to an arbitrary JSON value. + * Sets [Builder.browserbaseApiKey] to an arbitrary JSON value. * - * You should usually call [Builder.env] with a well-typed [Env] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.browserbaseApiKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. */ - fun env(env: JsonField) = apply { this.env = env } + fun browserbaseApiKey(browserbaseApiKey: JsonField) = apply { + this.browserbaseApiKey = browserbaseApiKey + } - /** API key for Browserbase (required when env=BROWSERBASE) */ - fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + /** Project ID for Browserbase */ + fun browserbaseProjectId(browserbaseProjectId: String) = + browserbaseProjectId(JsonField.of(browserbaseProjectId)) /** - * Sets [Builder.apiKey] to an arbitrary JSON value. + * Sets [Builder.browserbaseProjectId] to an arbitrary JSON value. * - * You should usually call [Builder.apiKey] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.browserbaseProjectId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. */ - fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + fun browserbaseProjectId(browserbaseProjectId: JsonField) = apply { + this.browserbaseProjectId = browserbaseProjectId + } /** Timeout in ms to wait for DOM to settle */ fun domSettleTimeout(domSettleTimeout: Long) = @@ -768,22 +686,7 @@ private constructor( this.domSettleTimeout = domSettleTimeout } - /** Options for local browser launch */ - fun localBrowserLaunchOptions(localBrowserLaunchOptions: LocalBrowserLaunchOptions) = - localBrowserLaunchOptions(JsonField.of(localBrowserLaunchOptions)) - - /** - * Sets [Builder.localBrowserLaunchOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.localBrowserLaunchOptions] with a well-typed - * [LocalBrowserLaunchOptions] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun localBrowserLaunchOptions( - localBrowserLaunchOptions: JsonField - ) = apply { this.localBrowserLaunchOptions = localBrowserLaunchOptions } - - /** AI model to use for actions */ + /** AI model to use for actions (must be prefixed with provider/) */ fun model(model: String) = model(JsonField.of(model)) /** @@ -795,18 +698,6 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Project ID for Browserbase (required when env=BROWSERBASE) */ - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** - * Sets [Builder.projectId] to an arbitrary JSON value. - * - * You should usually call [Builder.projectId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun projectId(projectId: JsonField) = apply { this.projectId = projectId } - /** Enable self-healing for failed actions */ fun selfHeal(selfHeal: Boolean) = selfHeal(JsonField.of(selfHeal)) @@ -871,19 +762,18 @@ private constructor( * * The following fields are required: * ```java - * .env() + * .browserbaseApiKey() + * .browserbaseProjectId() * ``` * * @throws IllegalStateException if any required field is unset. */ fun build(): Body = Body( - checkRequired("env", env), - apiKey, + checkRequired("browserbaseApiKey", browserbaseApiKey), + checkRequired("browserbaseProjectId", browserbaseProjectId), domSettleTimeout, - localBrowserLaunchOptions, model, - projectId, selfHeal, systemPrompt, verbose, @@ -898,12 +788,10 @@ private constructor( return@apply } - env().validate() - apiKey() + browserbaseApiKey() + browserbaseProjectId() domSettleTimeout() - localBrowserLaunchOptions().ifPresent { it.validate() } model() - projectId() selfHeal() systemPrompt() verbose() @@ -926,12 +814,10 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (env.asKnown().getOrNull()?.validity() ?: 0) + - (if (apiKey.asKnown().isPresent) 1 else 0) + + (if (browserbaseApiKey.asKnown().isPresent) 1 else 0) + + (if (browserbaseProjectId.asKnown().isPresent) 1 else 0) + (if (domSettleTimeout.asKnown().isPresent) 1 else 0) + - (localBrowserLaunchOptions.asKnown().getOrNull()?.validity() ?: 0) + (if (model.asKnown().isPresent) 1 else 0) + - (if (projectId.asKnown().isPresent) 1 else 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + (if (verbose.asKnown().isPresent) 1 else 0) @@ -942,12 +828,10 @@ private constructor( } return other is Body && - env == other.env && - apiKey == other.apiKey && + browserbaseApiKey == other.browserbaseApiKey && + browserbaseProjectId == other.browserbaseProjectId && domSettleTimeout == other.domSettleTimeout && - localBrowserLaunchOptions == other.localBrowserLaunchOptions && model == other.model && - projectId == other.projectId && selfHeal == other.selfHeal && systemPrompt == other.systemPrompt && verbose == other.verbose && @@ -956,12 +840,10 @@ private constructor( private val hashCode: Int by lazy { Objects.hash( - env, - apiKey, + browserbaseApiKey, + browserbaseProjectId, domSettleTimeout, - localBrowserLaunchOptions, model, - projectId, selfHeal, systemPrompt, verbose, @@ -972,280 +854,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Body{env=$env, apiKey=$apiKey, domSettleTimeout=$domSettleTimeout, localBrowserLaunchOptions=$localBrowserLaunchOptions, model=$model, projectId=$projectId, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, additionalProperties=$additionalProperties}" - } - - /** Environment to run the browser in */ - class Env @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val LOCAL = of("LOCAL") - - @JvmField val BROWSERBASE = of("BROWSERBASE") - - @JvmStatic fun of(value: String) = Env(JsonField.of(value)) - } - - /** An enum containing [Env]'s known values. */ - enum class Known { - LOCAL, - BROWSERBASE, - } - - /** - * An enum containing [Env]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Env] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - LOCAL, - BROWSERBASE, - /** An enum member indicating that [Env] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - LOCAL -> Value.LOCAL - BROWSERBASE -> Value.BROWSERBASE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - LOCAL -> Known.LOCAL - BROWSERBASE -> Known.BROWSERBASE - else -> throw StagehandInvalidDataException("Unknown Env: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Env = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Env && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - /** Options for local browser launch */ - class LocalBrowserLaunchOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val headless: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("headless") - @ExcludeMissing - headless: JsonField = JsonMissing.of() - ) : this(headless, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun headless(): Optional = headless.getOptional("headless") - - /** - * Returns the raw JSON value of [headless]. - * - * Unlike [headless], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("headless") @ExcludeMissing fun _headless(): JsonField = headless - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [LocalBrowserLaunchOptions]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [LocalBrowserLaunchOptions]. */ - class Builder internal constructor() { - - private var headless: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(localBrowserLaunchOptions: LocalBrowserLaunchOptions) = apply { - headless = localBrowserLaunchOptions.headless - additionalProperties = localBrowserLaunchOptions.additionalProperties.toMutableMap() - } - - fun headless(headless: Boolean) = headless(JsonField.of(headless)) - - /** - * Sets [Builder.headless] to an arbitrary JSON value. - * - * You should usually call [Builder.headless] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun headless(headless: JsonField) = apply { this.headless = headless } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [LocalBrowserLaunchOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): LocalBrowserLaunchOptions = - LocalBrowserLaunchOptions(headless, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): LocalBrowserLaunchOptions = apply { - if (validated) { - return@apply - } - - headless() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (headless.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is LocalBrowserLaunchOptions && - headless == other.headless && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(headless, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "LocalBrowserLaunchOptions{headless=$headless, additionalProperties=$additionalProperties}" + "Body{browserbaseApiKey=$browserbaseApiKey, browserbaseProjectId=$browserbaseProjectId, domSettleTimeout=$domSettleTimeout, model=$model, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 1c7e4d8..9454bf3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -10,14 +10,10 @@ internal class SessionStartParamsTest { @Test fun create() { SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -28,14 +24,10 @@ internal class SessionStartParamsTest { fun body() { val params = SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -43,13 +35,10 @@ internal class SessionStartParamsTest { val body = params._body() - assertThat(body.env()).isEqualTo(SessionStartParams.Env.LOCAL) - assertThat(body.apiKey()).contains("apiKey") + assertThat(body.browserbaseApiKey()).isEqualTo("BROWSERBASE_API_KEY") + assertThat(body.browserbaseProjectId()).isEqualTo("BROWSERBASE_PROJECT_ID") assertThat(body.domSettleTimeout()).contains(0L) - assertThat(body.localBrowserLaunchOptions()) - .contains(SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build()) assertThat(body.model()).contains("openai/gpt-4o") - assertThat(body.projectId()).contains("projectId") assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") assertThat(body.verbose()).contains(1L) @@ -57,10 +46,15 @@ internal class SessionStartParamsTest { @Test fun bodyWithoutOptionalFields() { - val params = SessionStartParams.builder().env(SessionStartParams.Env.LOCAL).build() + val params = + SessionStartParams.builder() + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") + .build() val body = params._body() - assertThat(body.env()).isEqualTo(SessionStartParams.Env.LOCAL) + assertThat(body.browserbaseApiKey()).isEqualTo("BROWSERBASE_API_KEY") + assertThat(body.browserbaseProjectId()).isEqualTo("BROWSERBASE_PROJECT_ID") } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 1a59424..fb35d34 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -72,16 +72,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -108,16 +102,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -144,16 +132,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -180,16 +162,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -216,16 +192,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -252,16 +222,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -288,16 +252,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -324,16 +282,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -360,16 +312,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -396,16 +342,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -432,16 +372,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -468,16 +402,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -504,16 +432,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -540,16 +462,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -576,16 +492,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -612,16 +522,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -646,16 +550,10 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index d02d7c6..af106c9 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -5,6 +5,8 @@ package com.browserbase.api.services import com.browserbase.api.client.StagehandClient import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.ModelConfig +import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.equalTo @@ -44,14 +46,10 @@ internal class ServiceParamsTest { sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder().headless(true).build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) @@ -68,4 +66,48 @@ internal class ServiceParamsTest { .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) ) } + + @Disabled("Prism tests are disabled") + @Test + fun act() { + val sessionService = client.sessions() + stubFor(post(anyUrl()).willReturn(ok("{}"))) + + sessionService.act( + SessionActParams.builder() + .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("click the sign in button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model( + ModelConfig.builder() + .apiKey("apiKey") + .baseUrl("https://example.com") + .model("model") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) + .timeout(0L) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) + .build() + ) + .putAdditionalHeader("Secret-Header", "42") + .putAdditionalQueryParam("secret_query_param", "42") + .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) + .build() + ) + + verify( + postRequestedFor(anyUrl()) + .withHeader("Secret-Header", equalTo("42")) + .withQueryParam("secret_query_param", equalTo("42")) + .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) + ) + } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 12cedb1..351ad55 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -240,16 +240,10 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index bc2c422..3a6781e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -234,16 +234,10 @@ internal class SessionServiceTest { val response = sessionService.start( SessionStartParams.builder() - .env(SessionStartParams.Env.LOCAL) - .apiKey("apiKey") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .domSettleTimeout(0L) - .localBrowserLaunchOptions( - SessionStartParams.LocalBrowserLaunchOptions.builder() - .headless(true) - .build() - ) .model("openai/gpt-4o") - .projectId("projectId") .selfHeal(true) .systemPrompt("systemPrompt") .verbose(1L) From 85a5896389a29a19c383c60a79d2d33f08d4db17 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 19:40:05 +0000 Subject: [PATCH 016/164] feat(api): manual updates --- .stats.yml | 4 +- .../models/sessions/SessionExtractResponse.kt | 54 +++++++++---------- .../sessions/SessionExtractResponseTest.kt | 18 +++---- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4664845..54cc978 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-6a22863a7da4fa45f904657a4cb8fc1a28e236925f03dc94fca25fd8271ca6db.yml -openapi_spec_hash: d5c6108942ad79f39ea4ff1bee9b7996 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-3607b588cab78536eb7de9f6acffe8ddda1d34aebe5910c2147421aa6c16bf22.yml +openapi_spec_hash: fb507e8d38b4978a5717fbb144197868 config_hash: 2f1ec44e7e07906e07bdc6e075763da9 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index 322d090..6816259 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -33,7 +33,7 @@ import java.util.Optional class SessionExtractResponse private constructor( private val extraction: Extraction? = null, - private val unionMember1: UnionMember1? = null, + private val custom: Custom? = null, private val _json: JsonValue? = null, ) { @@ -41,24 +41,24 @@ private constructor( fun extraction(): Optional = Optional.ofNullable(extraction) /** Structured data matching provided schema */ - fun unionMember1(): Optional = Optional.ofNullable(unionMember1) + fun custom(): Optional = Optional.ofNullable(custom) fun isExtraction(): Boolean = extraction != null - fun isUnionMember1(): Boolean = unionMember1 != null + fun isCustom(): Boolean = custom != null /** Default extraction result */ fun asExtraction(): Extraction = extraction.getOrThrow("extraction") /** Structured data matching provided schema */ - fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") + fun asCustom(): Custom = custom.getOrThrow("custom") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { extraction != null -> visitor.visitExtraction(extraction) - unionMember1 != null -> visitor.visitUnionMember1(unionMember1) + custom != null -> visitor.visitCustom(custom) else -> visitor.unknown(_json) } @@ -75,8 +75,8 @@ private constructor( extraction.validate() } - override fun visitUnionMember1(unionMember1: UnionMember1) { - unionMember1.validate() + override fun visitCustom(custom: Custom) { + custom.validate() } } ) @@ -102,7 +102,7 @@ private constructor( object : Visitor { override fun visitExtraction(extraction: Extraction) = extraction.validity() - override fun visitUnionMember1(unionMember1: UnionMember1) = unionMember1.validity() + override fun visitCustom(custom: Custom) = custom.validity() override fun unknown(json: JsonValue?) = 0 } @@ -115,15 +115,15 @@ private constructor( return other is SessionExtractResponse && extraction == other.extraction && - unionMember1 == other.unionMember1 + custom == other.custom } - override fun hashCode(): Int = Objects.hash(extraction, unionMember1) + override fun hashCode(): Int = Objects.hash(extraction, custom) override fun toString(): String = when { extraction != null -> "SessionExtractResponse{extraction=$extraction}" - unionMember1 != null -> "SessionExtractResponse{unionMember1=$unionMember1}" + custom != null -> "SessionExtractResponse{custom=$custom}" _json != null -> "SessionExtractResponse{_unknown=$_json}" else -> throw IllegalStateException("Invalid SessionExtractResponse") } @@ -135,9 +135,7 @@ private constructor( fun ofExtraction(extraction: Extraction) = SessionExtractResponse(extraction = extraction) /** Structured data matching provided schema */ - @JvmStatic - fun ofUnionMember1(unionMember1: UnionMember1) = - SessionExtractResponse(unionMember1 = unionMember1) + @JvmStatic fun ofCustom(custom: Custom) = SessionExtractResponse(custom = custom) } /** @@ -150,7 +148,7 @@ private constructor( fun visitExtraction(extraction: Extraction): T /** Structured data matching provided schema */ - fun visitUnionMember1(unionMember1: UnionMember1): T + fun visitCustom(custom: Custom): T /** * Maps an unknown variant of [SessionExtractResponse] to a value of type [T]. @@ -178,8 +176,8 @@ private constructor( tryDeserialize(node, jacksonTypeRef())?.let { SessionExtractResponse(extraction = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef())?.let { - SessionExtractResponse(unionMember1 = it, _json = json) + tryDeserialize(node, jacksonTypeRef())?.let { + SessionExtractResponse(custom = it, _json = json) }, ) .filterNotNull() @@ -207,7 +205,7 @@ private constructor( ) { when { value.extraction != null -> generator.writeObject(value.extraction) - value.unionMember1 != null -> generator.writeObject(value.unionMember1) + value.custom != null -> generator.writeObject(value.custom) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid SessionExtractResponse") } @@ -358,7 +356,7 @@ private constructor( } /** Structured data matching provided schema */ - class UnionMember1 + class Custom @JsonCreator private constructor( @com.fasterxml.jackson.annotation.JsonValue @@ -373,18 +371,18 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [UnionMember1]. */ + /** Returns a mutable builder for constructing an instance of [Custom]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [UnionMember1]. */ + /** A builder for [Custom]. */ class Builder internal constructor() { private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(unionMember1: UnionMember1) = apply { - additionalProperties = unionMember1.additionalProperties.toMutableMap() + internal fun from(custom: Custom) = apply { + additionalProperties = custom.additionalProperties.toMutableMap() } fun additionalProperties(additionalProperties: Map) = apply { @@ -407,16 +405,16 @@ private constructor( } /** - * Returns an immutable instance of [UnionMember1]. + * Returns an immutable instance of [Custom]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): UnionMember1 = UnionMember1(additionalProperties.toImmutable()) + fun build(): Custom = Custom(additionalProperties.toImmutable()) } private var validated: Boolean = false - fun validate(): UnionMember1 = apply { + fun validate(): Custom = apply { if (validated) { return@apply } @@ -447,13 +445,13 @@ private constructor( return true } - return other is UnionMember1 && additionalProperties == other.additionalProperties + return other is Custom && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { Objects.hash(additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "UnionMember1{additionalProperties=$additionalProperties}" + override fun toString() = "Custom{additionalProperties=$additionalProperties}" } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt index 2bd928d..42022d5 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt @@ -22,7 +22,7 @@ internal class SessionExtractResponseTest { val sessionExtractResponse = SessionExtractResponse.ofExtraction(extraction) assertThat(sessionExtractResponse.extraction()).contains(extraction) - assertThat(sessionExtractResponse.unionMember1()).isEmpty + assertThat(sessionExtractResponse.custom()).isEmpty } @Test @@ -43,24 +43,24 @@ internal class SessionExtractResponseTest { } @Test - fun ofUnionMember1() { - val unionMember1 = - SessionExtractResponse.UnionMember1.builder() + fun ofCustom() { + val custom = + SessionExtractResponse.Custom.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) .build() - val sessionExtractResponse = SessionExtractResponse.ofUnionMember1(unionMember1) + val sessionExtractResponse = SessionExtractResponse.ofCustom(custom) assertThat(sessionExtractResponse.extraction()).isEmpty - assertThat(sessionExtractResponse.unionMember1()).contains(unionMember1) + assertThat(sessionExtractResponse.custom()).contains(custom) } @Test - fun ofUnionMember1Roundtrip() { + fun ofCustomRoundtrip() { val jsonMapper = jsonMapper() val sessionExtractResponse = - SessionExtractResponse.ofUnionMember1( - SessionExtractResponse.UnionMember1.builder() + SessionExtractResponse.ofCustom( + SessionExtractResponse.Custom.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) From 02b71bfa8c6b2fc2d75769310b5f5fbdc0dd743f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 20:08:15 +0000 Subject: [PATCH 017/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 51 ++++------ .../api/client/okhttp/OkHttpClient.kt | 6 +- .../client/okhttp/StagehandOkHttpClient.kt | 23 ++--- .../okhttp/StagehandOkHttpClientAsync.kt | 23 ++--- .../com/browserbase/api/core/ClientOptions.kt | 92 ++++++++++++------- .../browserbase/api/core/ClientOptionsTest.kt | 7 +- .../api/services/ErrorHandlingTest.kt | 4 +- .../api/services/ServiceParamsTest.kt | 4 +- .../services/async/SessionServiceAsyncTest.kt | 28 ++++-- .../services/blocking/SessionServiceTest.kt | 28 ++++-- .../api/proguard/ProGuardCompatibilityTest.kt | 7 +- 12 files changed, 168 insertions(+), 107 deletions(-) diff --git a/.stats.yml b/.stats.yml index 54cc978..1e16065 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-3607b588cab78536eb7de9f6acffe8ddda1d34aebe5910c2147421aa6c16bf22.yml openapi_spec_hash: fb507e8d38b4978a5717fbb144197868 -config_hash: 2f1ec44e7e07906e07bdc6e075763da9 +config_hash: fc6606301b5142487a69d296f154b265 diff --git a/README.md b/README.md index a71554c..0097606 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ import com.browserbase.api.client.okhttp.StagehandOkHttpClient; import com.browserbase.api.models.sessions.SessionActParams; import com.browserbase.api.models.sessions.SessionActResponse; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +// Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties +// Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() @@ -70,8 +70,8 @@ Configure the client using system properties or environment variables: import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +// Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties +// Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); ``` @@ -82,7 +82,9 @@ import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; StagehandClient client = StagehandOkHttpClient.builder() - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build(); ``` @@ -93,19 +95,21 @@ import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; StagehandClient client = StagehandOkHttpClient.builder() - // Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties - // Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables + // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties + // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables .fromEnv() - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") .build(); ``` See this table for the available options: -| Setter | System property | Environment variable | Required | Default value | -| --------- | ------------------- | -------------------- | -------- | -------------------------------------------- | -| `apiKey` | `stagehand.apiKey` | `STAGEHAND_API_KEY` | true | - | -| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | +| Setter | System property | Environment variable | Required | Default value | +| ---------------------- | -------------------------------- | ------------------------ | -------- | -------------------------------------------- | +| `browserbaseApiKey` | `stagehand.browserbaseApiKey` | `BROWSERBASE_API_KEY` | true | - | +| `browserbaseProjectId` | `stagehand.browserbaseProjectId` | `BROWSERBASE_PROJECT_ID` | true | - | +| `modelApiKey` | `stagehand.modelApiKey` | `MODEL_API_KEY` | false | - | +| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | System properties take precedence over environment variables. @@ -153,8 +157,8 @@ import com.browserbase.api.models.sessions.SessionActParams; import com.browserbase.api.models.sessions.SessionActResponse; import java.util.concurrent.CompletableFuture; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +// Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties +// Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() @@ -173,8 +177,8 @@ import com.browserbase.api.models.sessions.SessionActParams; import com.browserbase.api.models.sessions.SessionActResponse; import java.util.concurrent.CompletableFuture; -// Configures using the `stagehand.apiKey` and `stagehand.baseUrl` system properties -// Or configures using the `STAGEHAND_API_KEY` and `STAGEHAND_BASE_URL` environment variables +// Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties +// Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); SessionActParams params = SessionActParams.builder() @@ -370,21 +374,6 @@ StagehandClient client = StagehandOkHttpClient.builder() .build(); ``` -### Environments - -The SDK sends requests to the production by default. To send requests to a different environment, configure the client like so: - -```java -import com.browserbase.api.client.StagehandClient; -import com.browserbase.api.client.okhttp.StagehandOkHttpClient; - -StagehandClient client = StagehandOkHttpClient.builder() - .fromEnv() - // Other options include `local` - .dev() - .build(); -``` - ### Custom HTTP client The SDK consists of three artifacts: diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index a624630..c03dd12 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -91,7 +91,11 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien } if (logLevel != null) { clientBuilder.addNetworkInterceptor( - HttpLoggingInterceptor().setLevel(logLevel).apply { redactHeader("Authorization") } + HttpLoggingInterceptor().setLevel(logLevel).apply { + redactHeader("x-bb-api-key") + redactHeader("x-bb-project-id") + redactHeader("x-model-api-key") + } ) } diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index 9114eb5..ced0665 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -145,22 +145,12 @@ class StagehandOkHttpClient private constructor() { * The base URL to use for every request. * * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. - * - * The following other environments, with dedicated builder methods, are available: - * - dev: `https://api.stagehand.dev.browserbase.com/v1` - * - local: `http://localhost:5000/v1` */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) - /** Sets [baseUrl] to `https://api.stagehand.dev.browserbase.com/v1`. */ - fun dev() = apply { clientOptions.dev() } - - /** Sets [baseUrl] to `http://localhost:5000/v1`. */ - fun local() = apply { clientOptions.local() } - /** * Whether to call `validate` on every response before returning it. * @@ -205,7 +195,18 @@ class StagehandOkHttpClient private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } - fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) } + fun browserbaseApiKey(browserbaseApiKey: String) = apply { + clientOptions.browserbaseApiKey(browserbaseApiKey) + } + + fun browserbaseProjectId(browserbaseProjectId: String) = apply { + clientOptions.browserbaseProjectId(browserbaseProjectId) + } + + fun modelApiKey(modelApiKey: String?) = apply { clientOptions.modelApiKey(modelApiKey) } + + /** Alias for calling [Builder.modelApiKey] with `modelApiKey.orElse(null)`. */ + fun modelApiKey(modelApiKey: Optional) = modelApiKey(modelApiKey.getOrNull()) fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index f16e2f8..e996038 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -145,22 +145,12 @@ class StagehandOkHttpClientAsync private constructor() { * The base URL to use for every request. * * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. - * - * The following other environments, with dedicated builder methods, are available: - * - dev: `https://api.stagehand.dev.browserbase.com/v1` - * - local: `http://localhost:5000/v1` */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) - /** Sets [baseUrl] to `https://api.stagehand.dev.browserbase.com/v1`. */ - fun dev() = apply { clientOptions.dev() } - - /** Sets [baseUrl] to `http://localhost:5000/v1`. */ - fun local() = apply { clientOptions.local() } - /** * Whether to call `validate` on every response before returning it. * @@ -205,7 +195,18 @@ class StagehandOkHttpClientAsync private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } - fun apiKey(apiKey: String) = apply { clientOptions.apiKey(apiKey) } + fun browserbaseApiKey(browserbaseApiKey: String) = apply { + clientOptions.browserbaseApiKey(browserbaseApiKey) + } + + fun browserbaseProjectId(browserbaseProjectId: String) = apply { + clientOptions.browserbaseProjectId(browserbaseProjectId) + } + + fun modelApiKey(modelApiKey: String?) = apply { clientOptions.modelApiKey(modelApiKey) } + + /** Alias for calling [Builder.modelApiKey] with `modelApiKey.orElse(null)`. */ + fun modelApiKey(modelApiKey: Optional) = modelApiKey(modelApiKey.getOrNull()) fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 967f4dc..4731cef 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -93,7 +93,9 @@ private constructor( * Defaults to 2. */ @get:JvmName("maxRetries") val maxRetries: Int, - @get:JvmName("apiKey") val apiKey: String, + @get:JvmName("browserbaseApiKey") val browserbaseApiKey: String, + @get:JvmName("browserbaseProjectId") val browserbaseProjectId: String, + private val modelApiKey: String?, ) { init { @@ -106,30 +108,25 @@ private constructor( * The base URL to use for every request. * * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. - * - * The following other environments, with dedicated builder methods, are available: - * - dev: `https://api.stagehand.dev.browserbase.com/v1` - * - local: `http://localhost:5000/v1` */ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL + fun modelApiKey(): Optional = Optional.ofNullable(modelApiKey) + fun toBuilder() = Builder().from(this) companion object { const val PRODUCTION_URL = "https://api.stagehand.browserbase.com/v1" - const val DEV_URL = "https://api.stagehand.dev.browserbase.com/v1" - - const val LOCAL_URL = "http://localhost:5000/v1" - /** * Returns a mutable builder for constructing an instance of [ClientOptions]. * * The following fields are required: * ```java * .httpClient() - * .apiKey() + * .browserbaseApiKey() + * .browserbaseProjectId() * ``` */ @JvmStatic fun builder() = Builder() @@ -156,7 +153,9 @@ private constructor( private var responseValidation: Boolean = false private var timeout: Timeout = Timeout.default() private var maxRetries: Int = 2 - private var apiKey: String? = null + private var browserbaseApiKey: String? = null + private var browserbaseProjectId: String? = null + private var modelApiKey: String? = null @JvmSynthetic internal fun from(clientOptions: ClientOptions) = apply { @@ -171,7 +170,9 @@ private constructor( responseValidation = clientOptions.responseValidation timeout = clientOptions.timeout maxRetries = clientOptions.maxRetries - apiKey = clientOptions.apiKey + browserbaseApiKey = clientOptions.browserbaseApiKey + browserbaseProjectId = clientOptions.browserbaseProjectId + modelApiKey = clientOptions.modelApiKey } /** @@ -228,22 +229,12 @@ private constructor( * The base URL to use for every request. * * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. - * - * The following other environments, with dedicated builder methods, are available: - * - dev: `https://api.stagehand.dev.browserbase.com/v1` - * - local: `http://localhost:5000/v1` */ fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl } /** Alias for calling [Builder.baseUrl] with `baseUrl.orElse(null)`. */ fun baseUrl(baseUrl: Optional) = baseUrl(baseUrl.getOrNull()) - /** Sets [baseUrl] to `https://api.stagehand.dev.browserbase.com/v1`. */ - fun dev() = baseUrl(DEV_URL) - - /** Sets [baseUrl] to `http://localhost:5000/v1`. */ - fun local() = baseUrl(LOCAL_URL) - /** * Whether to call `validate` on every response before returning it. * @@ -288,7 +279,18 @@ private constructor( */ fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } - fun apiKey(apiKey: String) = apply { this.apiKey = apiKey } + fun browserbaseApiKey(browserbaseApiKey: String) = apply { + this.browserbaseApiKey = browserbaseApiKey + } + + fun browserbaseProjectId(browserbaseProjectId: String) = apply { + this.browserbaseProjectId = browserbaseProjectId + } + + fun modelApiKey(modelApiKey: String?) = apply { this.modelApiKey = modelApiKey } + + /** Alias for calling [Builder.modelApiKey] with `modelApiKey.orElse(null)`. */ + fun modelApiKey(modelApiKey: Optional) = modelApiKey(modelApiKey.getOrNull()) fun headers(headers: Headers) = apply { this.headers.clear() @@ -377,10 +379,12 @@ private constructor( * * See this table for the available options: * - * |Setter |System property |Environment variable|Required|Default value | - * |---------|-------------------|--------------------|--------|--------------------------------------------| - * |`apiKey` |`stagehand.apiKey` |`STAGEHAND_API_KEY` |true |- | - * |`baseUrl`|`stagehand.baseUrl`|`STAGEHAND_BASE_URL`|true |`"https://api.stagehand.browserbase.com/v1"`| + * |Setter |System property |Environment variable |Required|Default value | + * |----------------------|--------------------------------|------------------------|--------|--------------------------------------------| + * |`browserbaseApiKey` |`stagehand.browserbaseApiKey` |`BROWSERBASE_API_KEY` |true |- | + * |`browserbaseProjectId`|`stagehand.browserbaseProjectId`|`BROWSERBASE_PROJECT_ID`|true |- | + * |`modelApiKey` |`stagehand.modelApiKey` |`MODEL_API_KEY` |false |- | + * |`baseUrl` |`stagehand.baseUrl` |`STAGEHAND_BASE_URL` |true |`"https://api.stagehand.browserbase.com/v1"`| * * System properties take precedence over environment variables. */ @@ -388,8 +392,14 @@ private constructor( (System.getProperty("stagehand.baseUrl") ?: System.getenv("STAGEHAND_BASE_URL"))?.let { baseUrl(it) } - (System.getProperty("stagehand.apiKey") ?: System.getenv("STAGEHAND_API_KEY"))?.let { - apiKey(it) + (System.getProperty("stagehand.browserbaseApiKey") + ?: System.getenv("BROWSERBASE_API_KEY")) + ?.let { browserbaseApiKey(it) } + (System.getProperty("stagehand.browserbaseProjectId") + ?: System.getenv("BROWSERBASE_PROJECT_ID")) + ?.let { browserbaseProjectId(it) } + (System.getProperty("stagehand.modelApiKey") ?: System.getenv("MODEL_API_KEY"))?.let { + modelApiKey(it) } } @@ -401,7 +411,8 @@ private constructor( * The following fields are required: * ```java * .httpClient() - * .apiKey() + * .browserbaseApiKey() + * .browserbaseProjectId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -409,7 +420,8 @@ private constructor( fun build(): ClientOptions { val httpClient = checkRequired("httpClient", httpClient) val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) - val apiKey = checkRequired("apiKey", apiKey) + val browserbaseApiKey = checkRequired("browserbaseApiKey", browserbaseApiKey) + val browserbaseProjectId = checkRequired("browserbaseProjectId", browserbaseProjectId) val headers = Headers.builder() val queryParams = QueryParams.builder() @@ -420,9 +432,19 @@ private constructor( headers.put("X-Stainless-Package-Version", getPackageVersion()) headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) - apiKey.let { + browserbaseApiKey.let { + if (!it.isEmpty()) { + headers.put("x-bb-api-key", it) + } + } + browserbaseProjectId.let { + if (!it.isEmpty()) { + headers.put("x-bb-project-id", it) + } + } + modelApiKey?.let { if (!it.isEmpty()) { - headers.put("Authorization", "Bearer $it") + headers.put("x-model-api-key", it) } } headers.replaceAll(this.headers.build()) @@ -446,7 +468,9 @@ private constructor( responseValidation, timeout, maxRetries, - apiKey, + browserbaseApiKey, + browserbaseProjectId, + modelApiKey, ) } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt index e73f724..75d56e8 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt @@ -19,7 +19,12 @@ internal class ClientOptionsTest { @Test fun toBuilder_whenOriginalClientOptionsGarbageCollected_doesNotCloseOriginalClient() { var clientOptions = - ClientOptions.builder().httpClient(httpClient).apiKey("My API Key").build() + ClientOptions.builder() + .httpClient(httpClient) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() verify(httpClient, never()).close() // Overwrite the `clientOptions` variable so that the original `ClientOptions` is GC'd. diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index fb35d34..509b889 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -54,7 +54,9 @@ internal class ErrorHandlingTest { client = StagehandOkHttpClient.builder() .baseUrl(wmRuntimeInfo.httpBaseUrl) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index af106c9..aa39440 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -34,7 +34,9 @@ internal class ServiceParamsTest { client = StagehandOkHttpClient.builder() .baseUrl(wmRuntimeInfo.httpBaseUrl) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 351ad55..d041842 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -26,7 +26,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() @@ -68,7 +70,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() @@ -84,7 +88,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() @@ -122,7 +128,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() @@ -165,7 +173,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() @@ -195,7 +205,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() @@ -233,7 +245,9 @@ internal class SessionServiceAsyncTest { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionServiceAsync = client.sessions() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 3a6781e..10177a3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -26,7 +26,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() @@ -67,7 +69,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() @@ -82,7 +86,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() @@ -119,7 +125,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() @@ -161,7 +169,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() @@ -190,7 +200,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() @@ -227,7 +239,9 @@ internal class SessionServiceTest { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) - .apiKey("My API Key") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") .build() val sessionService = client.sessions() diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 2ac121d..3960aa2 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -45,7 +45,12 @@ internal class ProGuardCompatibilityTest { @Test fun client() { - val client = StagehandOkHttpClient.builder().apiKey("My API Key").build() + val client = + StagehandOkHttpClient.builder() + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() assertThat(client).isNotNull() assertThat(client.sessions()).isNotNull() From 251ae78982ecf560c670b18fb46a88d2bccaa792 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 20:12:02 +0000 Subject: [PATCH 018/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 2 +- .../api/client/okhttp/StagehandOkHttpClient.kt | 5 +---- .../client/okhttp/StagehandOkHttpClientAsync.kt | 5 +---- .../com/browserbase/api/core/ClientOptions.kt | 16 +++++++--------- 5 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1e16065..44d6d13 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-3607b588cab78536eb7de9f6acffe8ddda1d34aebe5910c2147421aa6c16bf22.yml openapi_spec_hash: fb507e8d38b4978a5717fbb144197868 -config_hash: fc6606301b5142487a69d296f154b265 +config_hash: 9d54b9fd851ec7ac25b85f579be64425 diff --git a/README.md b/README.md index 0097606..273c14d 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ See this table for the available options: | ---------------------- | -------------------------------- | ------------------------ | -------- | -------------------------------------------- | | `browserbaseApiKey` | `stagehand.browserbaseApiKey` | `BROWSERBASE_API_KEY` | true | - | | `browserbaseProjectId` | `stagehand.browserbaseProjectId` | `BROWSERBASE_PROJECT_ID` | true | - | -| `modelApiKey` | `stagehand.modelApiKey` | `MODEL_API_KEY` | false | - | +| `modelApiKey` | `stagehand.modelApiKey` | `MODEL_API_KEY` | true | - | | `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | System properties take precedence over environment variables. diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index ced0665..eef8cff 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -203,10 +203,7 @@ class StagehandOkHttpClient private constructor() { clientOptions.browserbaseProjectId(browserbaseProjectId) } - fun modelApiKey(modelApiKey: String?) = apply { clientOptions.modelApiKey(modelApiKey) } - - /** Alias for calling [Builder.modelApiKey] with `modelApiKey.orElse(null)`. */ - fun modelApiKey(modelApiKey: Optional) = modelApiKey(modelApiKey.getOrNull()) + fun modelApiKey(modelApiKey: String) = apply { clientOptions.modelApiKey(modelApiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index e996038..53cda9d 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -203,10 +203,7 @@ class StagehandOkHttpClientAsync private constructor() { clientOptions.browserbaseProjectId(browserbaseProjectId) } - fun modelApiKey(modelApiKey: String?) = apply { clientOptions.modelApiKey(modelApiKey) } - - /** Alias for calling [Builder.modelApiKey] with `modelApiKey.orElse(null)`. */ - fun modelApiKey(modelApiKey: Optional) = modelApiKey(modelApiKey.getOrNull()) + fun modelApiKey(modelApiKey: String) = apply { clientOptions.modelApiKey(modelApiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 4731cef..46107c5 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -95,7 +95,7 @@ private constructor( @get:JvmName("maxRetries") val maxRetries: Int, @get:JvmName("browserbaseApiKey") val browserbaseApiKey: String, @get:JvmName("browserbaseProjectId") val browserbaseProjectId: String, - private val modelApiKey: String?, + @get:JvmName("modelApiKey") val modelApiKey: String, ) { init { @@ -111,8 +111,6 @@ private constructor( */ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL - fun modelApiKey(): Optional = Optional.ofNullable(modelApiKey) - fun toBuilder() = Builder().from(this) companion object { @@ -127,6 +125,7 @@ private constructor( * .httpClient() * .browserbaseApiKey() * .browserbaseProjectId() + * .modelApiKey() * ``` */ @JvmStatic fun builder() = Builder() @@ -287,10 +286,7 @@ private constructor( this.browserbaseProjectId = browserbaseProjectId } - fun modelApiKey(modelApiKey: String?) = apply { this.modelApiKey = modelApiKey } - - /** Alias for calling [Builder.modelApiKey] with `modelApiKey.orElse(null)`. */ - fun modelApiKey(modelApiKey: Optional) = modelApiKey(modelApiKey.getOrNull()) + fun modelApiKey(modelApiKey: String) = apply { this.modelApiKey = modelApiKey } fun headers(headers: Headers) = apply { this.headers.clear() @@ -383,7 +379,7 @@ private constructor( * |----------------------|--------------------------------|------------------------|--------|--------------------------------------------| * |`browserbaseApiKey` |`stagehand.browserbaseApiKey` |`BROWSERBASE_API_KEY` |true |- | * |`browserbaseProjectId`|`stagehand.browserbaseProjectId`|`BROWSERBASE_PROJECT_ID`|true |- | - * |`modelApiKey` |`stagehand.modelApiKey` |`MODEL_API_KEY` |false |- | + * |`modelApiKey` |`stagehand.modelApiKey` |`MODEL_API_KEY` |true |- | * |`baseUrl` |`stagehand.baseUrl` |`STAGEHAND_BASE_URL` |true |`"https://api.stagehand.browserbase.com/v1"`| * * System properties take precedence over environment variables. @@ -413,6 +409,7 @@ private constructor( * .httpClient() * .browserbaseApiKey() * .browserbaseProjectId() + * .modelApiKey() * ``` * * @throws IllegalStateException if any required field is unset. @@ -422,6 +419,7 @@ private constructor( val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) val browserbaseApiKey = checkRequired("browserbaseApiKey", browserbaseApiKey) val browserbaseProjectId = checkRequired("browserbaseProjectId", browserbaseProjectId) + val modelApiKey = checkRequired("modelApiKey", modelApiKey) val headers = Headers.builder() val queryParams = QueryParams.builder() @@ -442,7 +440,7 @@ private constructor( headers.put("x-bb-project-id", it) } } - modelApiKey?.let { + modelApiKey.let { if (!it.isEmpty()) { headers.put("x-model-api-key", it) } From 1570e8fbec437b9e399e90a16fbcef4b9faf53e9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 20:23:56 +0000 Subject: [PATCH 019/164] feat(api): manual updates --- .stats.yml | 6 +++--- .../browserbase/api/client/okhttp/StagehandOkHttpClient.kt | 3 +++ .../api/client/okhttp/StagehandOkHttpClientAsync.kt | 3 +++ .../main/kotlin/com/browserbase/api/core/ClientOptions.kt | 6 ++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 44d6d13..91b86f3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-3607b588cab78536eb7de9f6acffe8ddda1d34aebe5910c2147421aa6c16bf22.yml -openapi_spec_hash: fb507e8d38b4978a5717fbb144197868 -config_hash: 9d54b9fd851ec7ac25b85f579be64425 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c88c6d890406ff8a5f1bca692264fb9af4bc4fe64df0986e06d3386fc6d6fcb.yml +openapi_spec_hash: dc6ea17f8152708dc0a390c7f86b1a5d +config_hash: b01f15c540ab2c92808c2bba96368631 diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index eef8cff..8955635 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -195,14 +195,17 @@ class StagehandOkHttpClient private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ fun browserbaseApiKey(browserbaseApiKey: String) = apply { clientOptions.browserbaseApiKey(browserbaseApiKey) } + /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ fun browserbaseProjectId(browserbaseProjectId: String) = apply { clientOptions.browserbaseProjectId(browserbaseProjectId) } + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ fun modelApiKey(modelApiKey: String) = apply { clientOptions.modelApiKey(modelApiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 53cda9d..2cb208d 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -195,14 +195,17 @@ class StagehandOkHttpClientAsync private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ fun browserbaseApiKey(browserbaseApiKey: String) = apply { clientOptions.browserbaseApiKey(browserbaseApiKey) } + /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ fun browserbaseProjectId(browserbaseProjectId: String) = apply { clientOptions.browserbaseProjectId(browserbaseProjectId) } + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ fun modelApiKey(modelApiKey: String) = apply { clientOptions.modelApiKey(modelApiKey) } fun headers(headers: Headers) = apply { clientOptions.headers(headers) } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 46107c5..8692cb0 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -93,8 +93,11 @@ private constructor( * Defaults to 2. */ @get:JvmName("maxRetries") val maxRetries: Int, + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ @get:JvmName("browserbaseApiKey") val browserbaseApiKey: String, + /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ @get:JvmName("browserbaseProjectId") val browserbaseProjectId: String, + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ @get:JvmName("modelApiKey") val modelApiKey: String, ) { @@ -278,14 +281,17 @@ private constructor( */ fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ fun browserbaseApiKey(browserbaseApiKey: String) = apply { this.browserbaseApiKey = browserbaseApiKey } + /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ fun browserbaseProjectId(browserbaseProjectId: String) = apply { this.browserbaseProjectId = browserbaseProjectId } + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ fun modelApiKey(modelApiKey: String) = apply { this.modelApiKey = modelApiKey } fun headers(headers: Headers) = apply { From 4bfc263c2b548a67471be0a7b20b5101b5755510 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 20:33:37 +0000 Subject: [PATCH 020/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 91b86f3..35f1aef 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c88c6d890406ff8a5f1bca692264fb9af4bc4fe64df0986e06d3386fc6d6fcb.yml openapi_spec_hash: dc6ea17f8152708dc0a390c7f86b1a5d -config_hash: b01f15c540ab2c92808c2bba96368631 +config_hash: bdeeac521c2cf3846aec9f75cb681d97 diff --git a/README.md b/README.md index 273c14d..9c78d27 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ import com.browserbase.api.models.sessions.SessionActResponse; StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .sessionId("00000000-your-session-id-000000000000") .input("click the first link on the page") .build(); SessionActResponse response = client.sessions().act(params); @@ -162,7 +162,7 @@ import java.util.concurrent.CompletableFuture; StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .sessionId("00000000-your-session-id-000000000000") .input("click the first link on the page") .build(); CompletableFuture response = client.async().sessions().act(params); @@ -182,7 +182,7 @@ import java.util.concurrent.CompletableFuture; StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); SessionActParams params = SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + .sessionId("00000000-your-session-id-000000000000") .input("click the first link on the page") .build(); CompletableFuture response = client.sessions().act(params); @@ -203,8 +203,8 @@ import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") + .browserbaseApiKey("") + .browserbaseProjectId("") .build(); HttpResponseFor response = client.sessions().withRawResponse().start(params); From bd0e611801d99ae8d25c7ed4f08889b6227ef06f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 21:15:46 +0000 Subject: [PATCH 021/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 35f1aef..d9fd06e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c88c6d890406ff8a5f1bca692264fb9af4bc4fe64df0986e06d3386fc6d6fcb.yml openapi_spec_hash: dc6ea17f8152708dc0a390c7f86b1a5d -config_hash: bdeeac521c2cf3846aec9f75cb681d97 +config_hash: a17b6052ac65237b7b8e145f4f692d3c From d18d8ba114a0afe2b79c94fbc5ee0c13669722f9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:20:11 +0000 Subject: [PATCH 022/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1332969..3d2ac0b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1" + ".": "0.1.0" } \ No newline at end of file diff --git a/README.md b/README.md index 9c78d27..54118d3 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.0.1) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.0.1) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.1.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.1.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.1.0) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.0.1). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.1.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.0.1") +implementation("com.browserbase.api:stagehand-java:0.1.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.browserbase.api:stagehand-java:0.0.1") com.browserbase.api stagehand-java - 0.0.1 + 0.1.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 0913290..a32fb45 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.0.1" // x-release-please-version + version = "0.1.0" // x-release-please-version } subprojects { From dfb72fc9a07e199bc148f7d97a2a67bb2f31987e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:21:15 +0000 Subject: [PATCH 023/164] feat(api): manual updates --- .stats.yml | 6 +- README.md | 4 +- .../sessions/SessionExecuteAgentResponse.kt | 66 ++----------------- .../SessionExecuteAgentResponseTest.kt | 14 +--- 4 files changed, 13 insertions(+), 77 deletions(-) diff --git a/.stats.yml b/.stats.yml index d9fd06e..4a47868 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c88c6d890406ff8a5f1bca692264fb9af4bc4fe64df0986e06d3386fc6d6fcb.yml -openapi_spec_hash: dc6ea17f8152708dc0a390c7f86b1a5d -config_hash: a17b6052ac65237b7b8e145f4f692d3c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e52e8d3513159931200e5d4bd32cfdc475fe6e7db6b8015c394f5625b5a3ce1f.yml +openapi_spec_hash: fa597eb985cd1c3ba03acf68d6416857 +config_hash: b138dc33d4d0880499266048be517958 diff --git a/README.md b/README.md index 54118d3..edca05c 100644 --- a/README.md +++ b/README.md @@ -203,8 +203,8 @@ import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() - .browserbaseApiKey("") - .browserbaseProjectId("") + .browserbaseApiKey("BROWSERBASE_API_KEY") + .browserbaseProjectId("BROWSERBASE_PROJECT_ID") .build(); HttpResponseFor response = client.sessions().withRawResponse().start(params); diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt index 08afed9..3c3af1d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt @@ -6,8 +6,6 @@ import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.checkKnown -import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -16,21 +14,18 @@ import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects import java.util.Optional -import kotlin.jvm.optionals.getOrNull class SessionExecuteAgentResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val message: JsonField, - private val steps: JsonField>, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), - @JsonProperty("steps") @ExcludeMissing steps: JsonField> = JsonMissing.of(), - ) : this(message, steps, mutableMapOf()) + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of() + ) : this(message, mutableMapOf()) /** * Final message from the agent @@ -40,14 +35,6 @@ private constructor( */ fun message(): Optional = message.getOptional("message") - /** - * Steps taken by the agent - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun steps(): Optional> = steps.getOptional("steps") - /** * Returns the raw JSON value of [message]. * @@ -55,13 +42,6 @@ private constructor( */ @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message - /** - * Returns the raw JSON value of [steps]. - * - * Unlike [steps], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("steps") @ExcludeMissing fun _steps(): JsonField> = steps - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -86,13 +66,11 @@ private constructor( class Builder internal constructor() { private var message: JsonField = JsonMissing.of() - private var steps: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionExecuteAgentResponse: SessionExecuteAgentResponse) = apply { message = sessionExecuteAgentResponse.message - steps = sessionExecuteAgentResponse.steps.map { it.toMutableList() } additionalProperties = sessionExecuteAgentResponse.additionalProperties.toMutableMap() } @@ -107,30 +85,6 @@ private constructor( */ fun message(message: JsonField) = apply { this.message = message } - /** Steps taken by the agent */ - fun steps(steps: List) = steps(JsonField.of(steps)) - - /** - * Sets [Builder.steps] to an arbitrary JSON value. - * - * You should usually call [Builder.steps] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun steps(steps: JsonField>) = apply { - this.steps = steps.map { it.toMutableList() } - } - - /** - * Adds a single [JsonValue] to [steps]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addStep(step: JsonValue) = apply { - steps = - (steps ?: JsonField.of(mutableListOf())).also { checkKnown("steps", it).add(step) } - } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -156,11 +110,7 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): SessionExecuteAgentResponse = - SessionExecuteAgentResponse( - message, - (steps ?: JsonMissing.of()).map { it.toImmutable() }, - additionalProperties.toMutableMap(), - ) + SessionExecuteAgentResponse(message, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -171,7 +121,6 @@ private constructor( } message() - steps() validated = true } @@ -188,9 +137,7 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic - internal fun validity(): Int = - (if (message.asKnown().isPresent) 1 else 0) + (steps.asKnown().getOrNull()?.size ?: 0) + @JvmSynthetic internal fun validity(): Int = (if (message.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -199,14 +146,13 @@ private constructor( return other is SessionExecuteAgentResponse && message == other.message && - steps == other.steps && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(message, steps, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(message, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "SessionExecuteAgentResponse{message=$message, steps=$steps, additionalProperties=$additionalProperties}" + "SessionExecuteAgentResponse{message=$message, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt index 3fb7223..4737af6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt @@ -2,10 +2,8 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -14,24 +12,16 @@ internal class SessionExecuteAgentResponseTest { @Test fun create() { val sessionExecuteAgentResponse = - SessionExecuteAgentResponse.builder() - .message("message") - .addStep(JsonValue.from(mapOf())) - .build() + SessionExecuteAgentResponse.builder().message("message").build() assertThat(sessionExecuteAgentResponse.message()).contains("message") - assertThat(sessionExecuteAgentResponse.steps().getOrNull()) - .containsExactly(JsonValue.from(mapOf())) } @Test fun roundtrip() { val jsonMapper = jsonMapper() val sessionExecuteAgentResponse = - SessionExecuteAgentResponse.builder() - .message("message") - .addStep(JsonValue.from(mapOf())) - .build() + SessionExecuteAgentResponse.builder().message("message").build() val roundtrippedSessionExecuteAgentResponse = jsonMapper.readValue( From 9aa38b77312229c34bb619d8dda41a780efbfde0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:22:57 +0000 Subject: [PATCH 024/164] feat(api): manual updates --- .stats.yml | 6 +++--- README.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4a47868..36782ae 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e52e8d3513159931200e5d4bd32cfdc475fe6e7db6b8015c394f5625b5a3ce1f.yml -openapi_spec_hash: fa597eb985cd1c3ba03acf68d6416857 -config_hash: b138dc33d4d0880499266048be517958 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-705638ac8966569986bd9ebb7c9761bf0016909e9f2753e77ceabb12c8049511.yml +openapi_spec_hash: a8fbbcaa38e91c7f97313620b42d8d62 +config_hash: a35b56eb05306a0f02e83c11d57f975f diff --git a/README.md b/README.md index edca05c..e019b4a 100644 --- a/README.md +++ b/README.md @@ -203,8 +203,8 @@ import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") + .browserbaseApiKey("your Browserbase API key") + .browserbaseProjectId("your Browserbase Project ID") .build(); HttpResponseFor response = client.sessions().withRawResponse().start(params); From 085cbef91809fe68f970c3bbd16343c9e7a9cb33 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 22:33:20 +0000 Subject: [PATCH 025/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3d2ac0b..10f3091 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0" + ".": "0.2.0" } \ No newline at end of file diff --git a/README.md b/README.md index e019b4a..c383ecb 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.1.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.1.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.1.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.2.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.2.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.2.0) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.1.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.2.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.1.0") +implementation("com.browserbase.api:stagehand-java:0.2.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.browserbase.api:stagehand-java:0.1.0") com.browserbase.api stagehand-java - 0.1.0 + 0.2.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index a32fb45..63a11b4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.1.0" // x-release-please-version + version = "0.2.0" // x-release-please-version } subprojects { From 5bafc9c8bf2dddc4bea9fb3ddd13c47db7d8bb80 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 02:13:36 +0000 Subject: [PATCH 026/164] feat(api): manual updates --- .stats.yml | 6 +- README.md | 105 +- .../browserbase/api/models/sessions/Action.kt | 170 +- .../api/models/sessions/ModelConfig.kt | 579 +++--- .../api/models/sessions/SessionActParams.kt | 1233 ------------- .../api/models/sessions/SessionActResponse.kt | 269 --- .../api/models/sessions/SessionEndParams.kt | 229 --- .../api/models/sessions/SessionEndResponse.kt | 153 -- .../sessions/SessionExecuteAgentParams.kt | 1547 ----------------- .../sessions/SessionExecuteAgentResponse.kt | 158 -- .../models/sessions/SessionExtractParams.kt | 1064 ------------ .../models/sessions/SessionExtractResponse.kt | 457 ----- .../models/sessions/SessionNavigateParams.kt | 992 ----------- .../sessions/SessionNavigateResponse.kt | 216 --- .../models/sessions/SessionObserveParams.kt | 902 ---------- .../api/models/sessions/SessionStartParams.kt | 758 +------- .../models/sessions/SessionStartResponse.kt | 115 +- .../api/services/async/SessionServiceAsync.kt | 444 +---- .../services/async/SessionServiceAsyncImpl.kt | 261 --- .../api/services/blocking/SessionService.kt | 441 +---- .../services/blocking/SessionServiceImpl.kt | 237 --- .../api/models/sessions/ActionTest.kt | 28 +- .../api/models/sessions/ModelConfigTest.kt | 68 +- .../models/sessions/SessionActParamsTest.kt | 166 -- .../models/sessions/SessionActResponseTest.kt | 69 - .../models/sessions/SessionEndParamsTest.kt | 24 - .../models/sessions/SessionEndResponseTest.kt | 32 - .../sessions/SessionExecuteAgentParamsTest.kt | 170 -- .../SessionExecuteAgentResponseTest.kt | 34 - .../sessions/SessionExtractParamsTest.kt | 158 -- .../sessions/SessionExtractResponseTest.kt | 94 - .../sessions/SessionNavigateParamsTest.kt | 111 -- .../sessions/SessionNavigateResponseTest.kt | 36 - .../sessions/SessionObserveParamsTest.kt | 136 -- .../models/sessions/SessionStartParamsTest.kt | 66 +- .../sessions/SessionStartResponseTest.kt | 16 +- .../api/services/ErrorHandlingTest.kt | 204 +-- .../api/services/ServiceParamsTest.kt | 61 +- .../services/async/SessionServiceAsyncTest.kt | 238 +-- .../services/blocking/SessionServiceTest.kt | 232 +-- .../api/proguard/ProGuardCompatibilityTest.kt | 26 +- 41 files changed, 738 insertions(+), 11567 deletions(-) delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt diff --git a/.stats.yml b/.stats.yml index 36782ae..f5e93e0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-705638ac8966569986bd9ebb7c9761bf0016909e9f2753e77ceabb12c8049511.yml -openapi_spec_hash: a8fbbcaa38e91c7f97313620b42d8d62 +configured_endpoints: 1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-516862e7e90968bc55ac44ce7ffe2d5c1f738c11757471c2b9e0e4cff9384f2c.yml +openapi_spec_hash: 19bbe52a6ae0eec7fc3f6698e831ee55 config_hash: a35b56eb05306a0f02e83c11d57f975f diff --git a/README.md b/README.md index c383ecb..ae4e26a 100644 --- a/README.md +++ b/README.md @@ -48,18 +48,14 @@ This library requires Java 8 or later. ```java import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -import com.browserbase.api.models.sessions.SessionActParams; -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); -SessionActParams params = SessionActParams.builder() - .sessionId("00000000-your-session-id-000000000000") - .input("click the first link on the page") - .build(); -SessionActResponse response = client.sessions().act(params); +SessionStartResponse response = client.sessions().start(); ``` ## Client configuration @@ -136,7 +132,7 @@ The `withOptions()` method does not affect the original client or service. To send a request to the Stagehand API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. -For example, `client.sessions().act(...)` should be called with an instance of `SessionActParams`, and it will return an instance of `SessionActResponse`. +For example, `client.sessions().start(...)` should be called with an instance of `SessionStartParams`, and it will return an instance of `SessionStartResponse`. ## Immutability @@ -153,19 +149,15 @@ The default client is synchronous. To switch to asynchronous execution, call the ```java import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -import com.browserbase.api.models.sessions.SessionActParams; -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); -SessionActParams params = SessionActParams.builder() - .sessionId("00000000-your-session-id-000000000000") - .input("click the first link on the page") - .build(); -CompletableFuture response = client.async().sessions().act(params); +CompletableFuture response = client.async().sessions().start(); ``` Or create an asynchronous client from the beginning: @@ -173,19 +165,15 @@ Or create an asynchronous client from the beginning: ```java import com.browserbase.api.client.StagehandClientAsync; import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync; -import com.browserbase.api.models.sessions.SessionActParams; -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; import java.util.concurrent.CompletableFuture; // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); -SessionActParams params = SessionActParams.builder() - .sessionId("00000000-your-session-id-000000000000") - .input("click the first link on the page") - .build(); -CompletableFuture response = client.sessions().act(params); +CompletableFuture response = client.sessions().start(); ``` The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. @@ -202,11 +190,7 @@ import com.browserbase.api.core.http.HttpResponseFor; import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; -SessionStartParams params = SessionStartParams.builder() - .browserbaseApiKey("your Browserbase API key") - .browserbaseProjectId("your Browserbase Project ID") - .build(); -HttpResponseFor response = client.sessions().withRawResponse().start(params); +HttpResponseFor response = client.sessions().withRawResponse().start(); int statusCode = response.statusCode(); Headers headers = response.headers(); @@ -315,9 +299,7 @@ To set a custom timeout, configure the method call using the `timeout` method: ```java import com.browserbase.api.models.sessions.SessionStartResponse; -SessionStartResponse response = client.sessions().start( - params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() -); +SessionStartResponse response = client.sessions().start(RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()); ``` Or configure the default for all method calls at the client level: @@ -420,9 +402,9 @@ To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQu ```java import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionStartParams; -SessionActParams params = SessionActParams.builder() +SessionStartParams params = SessionStartParams.builder() .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) @@ -431,30 +413,12 @@ SessionActParams params = SessionActParams.builder() These can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods. -To set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class: - -```java -import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionActParams; - -SessionActParams params = SessionActParams.builder() - .options(SessionActParams.Options.builder() - .putAdditionalProperty("secretProperty", JsonValue.from("42")) - .build()) - .build(); -``` - -These properties can be accessed on the nested built object later using the `_additionalProperties()` method. - To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) object to its setter: ```java -import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionStartParams; -SessionActParams params = SessionActParams.builder() - .input(JsonValue.from(42)) - .build(); +SessionStartParams params = SessionStartParams.builder().build(); ``` The most straightforward way to create a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) is using its `from(...)` method: @@ -496,20 +460,6 @@ JsonValue complexValue = JsonValue.from(Map.of( )); ``` -Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. - -To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt): - -```java -import com.browserbase.api.core.JsonMissing; -import com.browserbase.api.models.sessions.SessionActParams; - -SessionActParams params = SessionActParams.builder() - .input("click the sign in button") - .sessionId(JsonMissing.of()) - .build(); -``` - ### Response properties To access undocumented response properties, call the `_additionalProperties()` method: @@ -518,7 +468,7 @@ To access undocumented response properties, call the `_additionalProperties()` m import com.browserbase.api.core.JsonValue; import java.util.Map; -Map additionalProperties = client.sessions().act(params)._additionalProperties(); +Map additionalProperties = client.sessions().start(params)._additionalProperties(); JsonValue secretPropertyValue = additionalProperties.get("secretProperty"); String result = secretPropertyValue.accept(new JsonValue.Visitor<>() { @@ -546,22 +496,21 @@ To access a property's raw JSON value, which may be undocumented, call its `_` p ```java import com.browserbase.api.core.JsonField; -import com.browserbase.api.models.sessions.SessionActParams; import java.util.Optional; -JsonField input = client.sessions().act(params)._input(); +JsonField field = client.sessions().start(params)._field(); -if (input.isMissing()) { +if (field.isMissing()) { // The property is absent from the JSON response -} else if (input.isNull()) { +} else if (field.isNull()) { // The property was set to literal null } else { // Check if value was provided as a string // Other methods include `asNumber()`, `asBoolean()`, etc. - Optional jsonString = input.asString(); + Optional jsonString = field.asString(); // Try to deserialize into a custom type - MyClass myObject = input.asUnknown().orElseThrow().convert(MyClass.class); + MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class); } ``` @@ -574,19 +523,17 @@ By default, the SDK will not throw an exception in this case. It will throw [`St If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: ```java -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; -SessionActResponse response = client.sessions().act(params).validate(); +SessionStartResponse response = client.sessions().start(params).validate(); ``` Or configure the method call to validate the response using the `responseValidation` method: ```java -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; -SessionActResponse response = client.sessions().act( - params, RequestOptions.builder().responseValidation(true).build() -); +SessionStartResponse response = client.sessions().start(RequestOptions.builder().responseValidation(true).build()); ``` Or configure the default for all method calls at the client level: diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt index d30a40b..e9ae4bc 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt @@ -19,39 +19,28 @@ import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull +/** Action object returned by observe and used by act */ class Action @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val arguments: JsonField>, private val description: JsonField, - private val method: JsonField, private val selector: JsonField, - private val backendNodeId: JsonField, + private val arguments: JsonField>, + private val method: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("arguments") - @ExcludeMissing - arguments: JsonField> = JsonMissing.of(), @JsonProperty("description") @ExcludeMissing description: JsonField = JsonMissing.of(), - @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), @JsonProperty("selector") @ExcludeMissing selector: JsonField = JsonMissing.of(), - @JsonProperty("backendNodeId") + @JsonProperty("arguments") @ExcludeMissing - backendNodeId: JsonField = JsonMissing.of(), - ) : this(arguments, description, method, selector, backendNodeId, mutableMapOf()) - - /** - * Arguments for the method - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun arguments(): List = arguments.getRequired("arguments") + arguments: JsonField> = JsonMissing.of(), + @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), + ) : this(description, selector, arguments, method, mutableMapOf()) /** * Human-readable description of the action @@ -62,15 +51,7 @@ private constructor( fun description(): String = description.getRequired("description") /** - * Method to execute (e.g., "click", "fill") - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun method(): String = method.getRequired("method") - - /** - * CSS or XPath selector for the element + * CSS selector or XPath for the element * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -78,19 +59,20 @@ private constructor( fun selector(): String = selector.getRequired("selector") /** - * CDP backend node ID + * Arguments to pass to the method * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") + fun arguments(): Optional> = arguments.getOptional("arguments") /** - * Returns the raw JSON value of [arguments]. + * The method to execute (click, fill, etc.) * - * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected type. + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - @JsonProperty("arguments") @ExcludeMissing fun _arguments(): JsonField> = arguments + fun method(): Optional = method.getOptional("method") /** * Returns the raw JSON value of [description]. @@ -100,27 +82,25 @@ private constructor( @JsonProperty("description") @ExcludeMissing fun _description(): JsonField = description /** - * Returns the raw JSON value of [method]. + * Returns the raw JSON value of [selector]. * - * Unlike [method], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector /** - * Returns the raw JSON value of [selector]. + * Returns the raw JSON value of [arguments]. * - * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + @JsonProperty("arguments") @ExcludeMissing fun _arguments(): JsonField> = arguments /** - * Returns the raw JSON value of [backendNodeId]. + * Returns the raw JSON value of [method]. * - * Unlike [backendNodeId], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [method], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("backendNodeId") - @ExcludeMissing - fun _backendNodeId(): JsonField = backendNodeId + @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -141,9 +121,7 @@ private constructor( * * The following fields are required: * ```java - * .arguments() * .description() - * .method() * .selector() * ``` */ @@ -153,24 +131,45 @@ private constructor( /** A builder for [Action]. */ class Builder internal constructor() { - private var arguments: JsonField>? = null private var description: JsonField? = null - private var method: JsonField? = null private var selector: JsonField? = null - private var backendNodeId: JsonField = JsonMissing.of() + private var arguments: JsonField>? = null + private var method: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(action: Action) = apply { - arguments = action.arguments.map { it.toMutableList() } description = action.description - method = action.method selector = action.selector - backendNodeId = action.backendNodeId + arguments = action.arguments.map { it.toMutableList() } + method = action.method additionalProperties = action.additionalProperties.toMutableMap() } - /** Arguments for the method */ + /** Human-readable description of the action */ + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun description(description: JsonField) = apply { this.description = description } + + /** CSS selector or XPath for the element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** Arguments to pass to the method */ fun arguments(arguments: List) = arguments(JsonField.of(arguments)) /** @@ -196,19 +195,7 @@ private constructor( } } - /** Human-readable description of the action */ - fun description(description: String) = description(JsonField.of(description)) - - /** - * Sets [Builder.description] to an arbitrary JSON value. - * - * You should usually call [Builder.description] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun description(description: JsonField) = apply { this.description = description } - - /** Method to execute (e.g., "click", "fill") */ + /** The method to execute (click, fill, etc.) */ fun method(method: String) = method(JsonField.of(method)) /** @@ -219,31 +206,6 @@ private constructor( */ fun method(method: JsonField) = apply { this.method = method } - /** CSS or XPath selector for the element */ - fun selector(selector: String) = selector(JsonField.of(selector)) - - /** - * Sets [Builder.selector] to an arbitrary JSON value. - * - * You should usually call [Builder.selector] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun selector(selector: JsonField) = apply { this.selector = selector } - - /** CDP backend node ID */ - fun backendNodeId(backendNodeId: Long) = backendNodeId(JsonField.of(backendNodeId)) - - /** - * Sets [Builder.backendNodeId] to an arbitrary JSON value. - * - * You should usually call [Builder.backendNodeId] with a well-typed [Long] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun backendNodeId(backendNodeId: JsonField) = apply { - this.backendNodeId = backendNodeId - } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -270,9 +232,7 @@ private constructor( * * The following fields are required: * ```java - * .arguments() * .description() - * .method() * .selector() * ``` * @@ -280,11 +240,10 @@ private constructor( */ fun build(): Action = Action( - checkRequired("arguments", arguments).map { it.toImmutable() }, checkRequired("description", description), - checkRequired("method", method), checkRequired("selector", selector), - backendNodeId, + (arguments ?: JsonMissing.of()).map { it.toImmutable() }, + method, additionalProperties.toMutableMap(), ) } @@ -296,11 +255,10 @@ private constructor( return@apply } - arguments() description() - method() selector() - backendNodeId() + arguments() + method() validated = true } @@ -319,11 +277,10 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (arguments.asKnown().getOrNull()?.size ?: 0) + - (if (description.asKnown().isPresent) 1 else 0) + - (if (method.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + (if (selector.asKnown().isPresent) 1 else 0) + - (if (backendNodeId.asKnown().isPresent) 1 else 0) + (arguments.asKnown().getOrNull()?.size ?: 0) + + (if (method.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -331,20 +288,19 @@ private constructor( } return other is Action && - arguments == other.arguments && description == other.description && - method == other.method && selector == other.selector && - backendNodeId == other.backendNodeId && + arguments == other.arguments && + method == other.method && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(arguments, description, method, selector, backendNodeId, additionalProperties) + Objects.hash(description, selector, arguments, method, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Action{arguments=$arguments, description=$description, method=$method, selector=$selector, backendNodeId=$backendNodeId, additionalProperties=$additionalProperties}" + "Action{description=$description, selector=$selector, arguments=$arguments, method=$method, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index e08ebfa..0d210b0 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -2,205 +2,61 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional -import kotlin.jvm.optionals.getOrNull +@JsonDeserialize(using = ModelConfig.Deserializer::class) +@JsonSerialize(using = ModelConfig.Serializer::class) class ModelConfig -@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val apiKey: JsonField, - private val baseUrl: JsonField, - private val model: JsonField, - private val provider: JsonField, - private val additionalProperties: MutableMap, + private val string: String? = null, + private val unionMember1: UnionMember1? = null, + private val _json: JsonValue? = null, ) { - @JsonCreator - private constructor( - @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), - @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), - ) : this(apiKey, baseUrl, model, provider, mutableMapOf()) + fun string(): Optional = Optional.ofNullable(string) - /** - * API key for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun apiKey(): Optional = apiKey.getOptional("apiKey") + fun unionMember1(): Optional = Optional.ofNullable(unionMember1) - /** - * Custom base URL for API - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + fun isString(): Boolean = string != null - /** - * Model name - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun model(): Optional = model.getOptional("model") + fun isUnionMember1(): Boolean = unionMember1 != null - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun provider(): Optional = provider.getOptional("provider") + fun asString(): String = string.getOrThrow("string") - /** - * Returns the raw JSON value of [apiKey]. - * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") - /** - * Returns the raw JSON value of [baseUrl]. - * - * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + fun _json(): Optional = Optional.ofNullable(_json) - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - - /** - * Returns the raw JSON value of [provider]. - * - * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [ModelConfig]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ModelConfig]. */ - class Builder internal constructor() { - - private var apiKey: JsonField = JsonMissing.of() - private var baseUrl: JsonField = JsonMissing.of() - private var model: JsonField = JsonMissing.of() - private var provider: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(modelConfig: ModelConfig) = apply { - apiKey = modelConfig.apiKey - baseUrl = modelConfig.baseUrl - model = modelConfig.model - provider = modelConfig.provider - additionalProperties = modelConfig.additionalProperties.toMutableMap() + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + unionMember1 != null -> visitor.visitUnionMember1(unionMember1) + else -> visitor.unknown(_json) } - /** API key for the model provider */ - fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) - - /** - * Sets [Builder.apiKey] to an arbitrary JSON value. - * - * You should usually call [Builder.apiKey] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } - - /** Custom base URL for API */ - fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) - - /** - * Sets [Builder.baseUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.baseUrl] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - - /** Model name */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - - fun provider(provider: Provider) = provider(JsonField.of(provider)) - - /** - * Sets [Builder.provider] to an arbitrary JSON value. - * - * You should usually call [Builder.provider] with a well-typed [Provider] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun provider(provider: JsonField) = apply { this.provider = provider } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [ModelConfig]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): ModelConfig = - ModelConfig(apiKey, baseUrl, model, provider, additionalProperties.toMutableMap()) - } - private var validated: Boolean = false fun validate(): ModelConfig = apply { @@ -208,10 +64,15 @@ private constructor( return@apply } - apiKey() - baseUrl() - model() - provider().ifPresent { it.validate() } + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitUnionMember1(unionMember1: UnionMember1) { + unionMember1.validate() + } + } + ) validated = true } @@ -230,112 +91,291 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (apiKey.asKnown().isPresent) 1 else 0) + - (if (baseUrl.asKnown().isPresent) 1 else 0) + - (if (model.asKnown().isPresent) 1 else 0) + - (provider.asKnown().getOrNull()?.validity() ?: 0) + accept( + object : Visitor { + override fun visitString(string: String) = 1 - class Provider @JsonCreator private constructor(private val value: JsonField) : Enum { + override fun visitUnionMember1(unionMember1: UnionMember1) = unionMember1.validity() - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { + override fun unknown(json: JsonValue?) = 0 + } + ) - @JvmField val OPENAI = of("openai") + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - @JvmField val ANTHROPIC = of("anthropic") + return other is ModelConfig && string == other.string && unionMember1 == other.unionMember1 + } - @JvmField val GOOGLE = of("google") + override fun hashCode(): Int = Objects.hash(string, unionMember1) - @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) + override fun toString(): String = + when { + string != null -> "ModelConfig{string=$string}" + unionMember1 != null -> "ModelConfig{unionMember1=$unionMember1}" + _json != null -> "ModelConfig{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ModelConfig") } - /** An enum containing [Provider]'s known values. */ - enum class Known { - OPENAI, - ANTHROPIC, - GOOGLE, - } + companion object { + + @JvmStatic fun ofString(string: String) = ModelConfig(string = string) + + @JvmStatic + fun ofUnionMember1(unionMember1: UnionMember1) = ModelConfig(unionMember1 = unionMember1) + } + + /** + * An interface that defines how to map each variant of [ModelConfig] to a value of type [T]. + */ + interface Visitor { + + fun visitString(string: String): T + + fun visitUnionMember1(unionMember1: UnionMember1): T /** - * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. + * Maps an unknown variant of [ModelConfig] to a value of type [T]. + * + * An instance of [ModelConfig] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older version + * than the API, then the API may respond with new variants that the SDK is unaware of. * - * An instance of [Provider] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. + * @throws StagehandInvalidDataException in the default implementation. */ - enum class Value { - OPENAI, - ANTHROPIC, - GOOGLE, - /** An enum member indicating that [Provider] was instantiated with an unknown value. */ - _UNKNOWN, + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown ModelConfig: $json") } + } + + internal class Deserializer : BaseDeserializer(ModelConfig::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ModelConfig { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + ModelConfig(unionMember1 = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ModelConfig(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with all + // the possible variants (e.g. deserializing from array). + 0 -> ModelConfig(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(ModelConfig::class) { + + override fun serialize( + value: ModelConfig, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.unionMember1 != null -> generator.writeObject(value.unionMember1) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ModelConfig") + } + } + } + + class UnionMember1 + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val modelName: JsonField, + private val apiKey: JsonField, + private val baseUrl: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("modelName") + @ExcludeMissing + modelName: JsonField = JsonMissing.of(), + @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), + @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), + ) : this(modelName, apiKey, baseUrl, mutableMapOf()) /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun value(): Value = - when (this) { - OPENAI -> Value.OPENAI - ANTHROPIC -> Value.ANTHROPIC - GOOGLE -> Value.GOOGLE - else -> Value._UNKNOWN - } + fun modelName(): String = modelName.getRequired("modelName") /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun apiKey(): Optional = apiKey.getOptional("apiKey") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + + /** + * Returns the raw JSON value of [modelName]. * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. + * Unlike [modelName], this method doesn't throw if the JSON field has an unexpected type. */ - fun known(): Known = - when (this) { - OPENAI -> Known.OPENAI - ANTHROPIC -> Known.ANTHROPIC - GOOGLE -> Known.GOOGLE - else -> throw StagehandInvalidDataException("Unknown Provider: $value") - } + @JsonProperty("modelName") @ExcludeMissing fun _modelName(): JsonField = modelName /** - * Returns this class instance's primitive wire representation. + * Returns the raw JSON value of [apiKey]. * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + + /** + * Returns the raw JSON value of [baseUrl]. * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. + * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") + @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [UnionMember1]. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UnionMember1]. */ + class Builder internal constructor() { + + private var modelName: JsonField? = null + private var apiKey: JsonField = JsonMissing.of() + private var baseUrl: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(unionMember1: UnionMember1) = apply { + modelName = unionMember1.modelName + apiKey = unionMember1.apiKey + baseUrl = unionMember1.baseUrl + additionalProperties = unionMember1.additionalProperties.toMutableMap() + } + + fun modelName(modelName: String) = modelName(JsonField.of(modelName)) + + /** + * Sets [Builder.modelName] to an arbitrary JSON value. + * + * You should usually call [Builder.modelName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun modelName(modelName: JsonField) = apply { this.modelName = modelName } + + fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + + /** + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + + fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) + + /** + * Sets [Builder.baseUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.baseUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [UnionMember1]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): UnionMember1 = + UnionMember1( + checkRequired("modelName", modelName), + apiKey, + baseUrl, + additionalProperties.toMutableMap(), + ) + } + private var validated: Boolean = false - fun validate(): Provider = apply { + fun validate(): UnionMember1 = apply { if (validated) { return@apply } - known() + modelName() + apiKey() + baseUrl() validated = true } @@ -353,40 +393,31 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + @JvmSynthetic + internal fun validity(): Int = + (if (modelName.asKnown().isPresent) 1 else 0) + + (if (apiKey.asKnown().isPresent) 1 else 0) + + (if (baseUrl.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Provider && value == other.value + return other is UnionMember1 && + modelName == other.modelName && + apiKey == other.apiKey && + baseUrl == other.baseUrl && + additionalProperties == other.additionalProperties } - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true + private val hashCode: Int by lazy { + Objects.hash(modelName, apiKey, baseUrl, additionalProperties) } - return other is ModelConfig && - apiKey == other.apiKey && - baseUrl == other.baseUrl && - model == other.model && - provider == other.provider && - additionalProperties == other.additionalProperties - } + override fun hashCode(): Int = hashCode - private val hashCode: Int by lazy { - Objects.hash(apiKey, baseUrl, model, provider, additionalProperties) + override fun toString() = + "UnionMember1{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, additionalProperties=$additionalProperties}" } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "ModelConfig{apiKey=$apiKey, baseUrl=$baseUrl, model=$model, provider=$provider, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt deleted file mode 100644 index 34cae33..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ /dev/null @@ -1,1233 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.BaseDeserializer -import com.browserbase.api.core.BaseSerializer -import com.browserbase.api.core.Enum -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.allMaxBy -import com.browserbase.api.core.checkRequired -import com.browserbase.api.core.getOrThrow -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.ObjectCodec -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import com.fasterxml.jackson.databind.annotation.JsonSerialize -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.util.Collections -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** - * Performs a browser action based on natural language instruction or a specific action object - * returned by observe(). - */ -class SessionActParams -private constructor( - private val sessionId: String?, - private val xStreamResponse: XStreamResponse?, - private val body: Body, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun sessionId(): Optional = Optional.ofNullable(sessionId) - - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - - /** - * Natural language instruction - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun input(): Input = body.input() - - /** - * Frame ID to act on (optional) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun frameId(): Optional = body.frameId() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun options(): Optional = body.options() - - /** - * Returns the raw JSON value of [input]. - * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _input(): JsonField = body._input() - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _frameId(): JsonField = body._frameId() - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _options(): JsonField = body._options() - - fun _additionalBodyProperties(): Map = body._additionalProperties() - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [SessionActParams]. - * - * The following fields are required: - * ```java - * .input() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionActParams]. */ - class Builder internal constructor() { - - private var sessionId: String? = null - private var xStreamResponse: XStreamResponse? = null - private var body: Body.Builder = Body.builder() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(sessionActParams: SessionActParams) = apply { - sessionId = sessionActParams.sessionId - xStreamResponse = sessionActParams.xStreamResponse - body = sessionActParams.body.toBuilder() - additionalHeaders = sessionActParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionActParams.additionalQueryParams.toBuilder() - } - - fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } - - /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ - fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) - - fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { - this.xStreamResponse = xStreamResponse - } - - /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = - xStreamResponse(xStreamResponse.getOrNull()) - - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [input] - * - [frameId] - * - [options] - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - /** Natural language instruction */ - fun input(input: Input) = apply { body.input(input) } - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed [Input] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun input(input: JsonField) = apply { body.input(input) } - - /** Alias for calling [input] with `Input.ofString(string)`. */ - fun input(string: String) = apply { body.input(string) } - - /** Alias for calling [input] with `Input.ofAction(action)`. */ - fun input(action: Action) = apply { body.input(action) } - - /** Frame ID to act on (optional) */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } - - fun options(options: Options) = apply { body.options(options) } - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun options(options: JsonField) = apply { body.options(options) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [SessionActParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .input() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): SessionActParams = - SessionActParams( - sessionId, - xStreamResponse, - body.build(), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): Body = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> sessionId ?: "" - else -> "" - } - - override fun _headers(): Headers = - Headers.builder() - .apply { - xStreamResponse?.let { put("x-stream-response", it.toString()) } - putAll(additionalHeaders) - } - .build() - - override fun _queryParams(): QueryParams = additionalQueryParams - - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val input: JsonField, - private val frameId: JsonField, - private val options: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), - @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), - @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), - ) : this(input, frameId, options, mutableMapOf()) - - /** - * Natural language instruction - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun input(): Input = input.getRequired("input") - - /** - * Frame ID to act on (optional) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun frameId(): Optional = frameId.getOptional("frameId") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun options(): Optional = options.getOptional("options") - - /** - * Returns the raw JSON value of [input]. - * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Body]. - * - * The following fields are required: - * ```java - * .input() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var input: JsonField? = null - private var frameId: JsonField = JsonMissing.of() - private var options: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - input = body.input - frameId = body.frameId - options = body.options - additionalProperties = body.additionalProperties.toMutableMap() - } - - /** Natural language instruction */ - fun input(input: Input) = input(JsonField.of(input)) - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed [Input] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun input(input: JsonField) = apply { this.input = input } - - /** Alias for calling [input] with `Input.ofString(string)`. */ - fun input(string: String) = input(Input.ofString(string)) - - /** Alias for calling [input] with `Input.ofAction(action)`. */ - fun input(action: Action) = input(Input.ofAction(action)) - - /** Frame ID to act on (optional) */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun frameId(frameId: JsonField) = apply { this.frameId = frameId } - - fun options(options: Options) = options(JsonField.of(options)) - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun options(options: JsonField) = apply { this.options = options } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .input() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Body = - Body( - checkRequired("input", input), - frameId, - options, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - input().validate() - frameId() - options().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (input.asKnown().getOrNull()?.validity() ?: 0) + - (if (frameId.asKnown().isPresent) 1 else 0) + - (options.asKnown().getOrNull()?.validity() ?: 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - input == other.input && - frameId == other.frameId && - options == other.options && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(input, frameId, options, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{input=$input, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" - } - - /** Natural language instruction */ - @JsonDeserialize(using = Input.Deserializer::class) - @JsonSerialize(using = Input.Serializer::class) - class Input - private constructor( - private val string: String? = null, - private val action: Action? = null, - private val _json: JsonValue? = null, - ) { - - /** Natural language instruction */ - fun string(): Optional = Optional.ofNullable(string) - - fun action(): Optional = Optional.ofNullable(action) - - fun isString(): Boolean = string != null - - fun isAction(): Boolean = action != null - - /** Natural language instruction */ - fun asString(): String = string.getOrThrow("string") - - fun asAction(): Action = action.getOrThrow("action") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - string != null -> visitor.visitString(string) - action != null -> visitor.visitAction(action) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Input = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitString(string: String) {} - - override fun visitAction(action: Action) { - action.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitString(string: String) = 1 - - override fun visitAction(action: Action) = action.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Input && string == other.string && action == other.action - } - - override fun hashCode(): Int = Objects.hash(string, action) - - override fun toString(): String = - when { - string != null -> "Input{string=$string}" - action != null -> "Input{action=$action}" - _json != null -> "Input{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Input") - } - - companion object { - - /** Natural language instruction */ - @JvmStatic fun ofString(string: String) = Input(string = string) - - @JvmStatic fun ofAction(action: Action) = Input(action = action) - } - - /** An interface that defines how to map each variant of [Input] to a value of type [T]. */ - interface Visitor { - - /** Natural language instruction */ - fun visitString(string: String): T - - fun visitAction(action: Action): T - - /** - * Maps an unknown variant of [Input] to a value of type [T]. - * - * An instance of [Input] can contain an unknown variant if it was deserialized from - * data that doesn't match any known variant. For example, if the SDK is on an older - * version than the API, then the API may respond with new variants that the SDK is - * unaware of. - * - * @throws StagehandInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown Input: $json") - } - } - - internal class Deserializer : BaseDeserializer(Input::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Input { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef())?.let { - Input(action = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Input(string = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible with - // all the possible variants (e.g. deserializing from array). - 0 -> Input(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the first - // completely valid match, or simply the first match if none are completely - // valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Input::class) { - - override fun serialize( - value: Input, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.action != null -> generator.writeObject(value.action) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Input") - } - } - } - } - - class Options - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val model: JsonField, - private val timeout: JsonField, - private val variables: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), - @JsonProperty("variables") - @ExcludeMissing - variables: JsonField = JsonMissing.of(), - ) : this(model, timeout, variables, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun model(): Optional = model.getOptional("model") - - /** - * Timeout in milliseconds - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun timeout(): Optional = timeout.getOptional("timeout") - - /** - * Template variables for instruction - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun variables(): Optional = variables.getOptional("variables") - - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - - /** - * Returns the raw JSON value of [timeout]. - * - * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout - - /** - * Returns the raw JSON value of [variables]. - * - * Unlike [variables], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("variables") - @ExcludeMissing - fun _variables(): JsonField = variables - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Options]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Options]. */ - class Builder internal constructor() { - - private var model: JsonField = JsonMissing.of() - private var timeout: JsonField = JsonMissing.of() - private var variables: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(options: Options) = apply { - model = options.model - timeout = options.timeout - variables = options.variables - additionalProperties = options.additionalProperties.toMutableMap() - } - - fun model(model: ModelConfig) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - - /** Timeout in milliseconds */ - fun timeout(timeout: Long) = timeout(JsonField.of(timeout)) - - /** - * Sets [Builder.timeout] to an arbitrary JSON value. - * - * You should usually call [Builder.timeout] with a well-typed [Long] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun timeout(timeout: JsonField) = apply { this.timeout = timeout } - - /** Template variables for instruction */ - fun variables(variables: Variables) = variables(JsonField.of(variables)) - - /** - * Sets [Builder.variables] to an arbitrary JSON value. - * - * You should usually call [Builder.variables] with a well-typed [Variables] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun variables(variables: JsonField) = apply { this.variables = variables } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Options]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Options = - Options(model, timeout, variables, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Options = apply { - if (validated) { - return@apply - } - - model().ifPresent { it.validate() } - timeout() - variables().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (model.asKnown().getOrNull()?.validity() ?: 0) + - (if (timeout.asKnown().isPresent) 1 else 0) + - (variables.asKnown().getOrNull()?.validity() ?: 0) - - /** Template variables for instruction */ - class Variables - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Variables]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Variables]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(variables: Variables) = apply { - additionalProperties = variables.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Variables]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Variables = Variables(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Variables = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Variables && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Variables{additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Options && - model == other.model && - timeout == other.timeout && - variables == other.variables && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(model, timeout, variables, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Options{model=$model, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" - } - - class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of("true") - - @JvmField val FALSE = of("false") - - @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) - } - - /** An enum containing [XStreamResponse]'s known values. */ - enum class Known { - TRUE, - FALSE, - } - - /** - * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - FALSE, - /** - * An enum member indicating that [XStreamResponse] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - FALSE -> Value.FALSE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XStreamResponse = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XStreamResponse && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionActParams && - sessionId == other.sessionId && - xStreamResponse == other.xStreamResponse && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "SessionActParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt deleted file mode 100644 index 69dfcab..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt +++ /dev/null @@ -1,269 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.checkKnown -import com.browserbase.api.core.checkRequired -import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import kotlin.jvm.optionals.getOrNull - -class SessionActResponse -@JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor( - private val actions: JsonField>, - private val message: JsonField, - private val success: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("actions") - @ExcludeMissing - actions: JsonField> = JsonMissing.of(), - @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), - ) : this(actions, message, success, mutableMapOf()) - - /** - * Actions that were executed - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun actions(): List = actions.getRequired("actions") - - /** - * Result message - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun message(): String = message.getRequired("message") - - /** - * Whether the action succeeded - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun success(): Boolean = success.getRequired("success") - - /** - * Returns the raw JSON value of [actions]. - * - * Unlike [actions], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("actions") @ExcludeMissing fun _actions(): JsonField> = actions - - /** - * Returns the raw JSON value of [message]. - * - * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message - - /** - * Returns the raw JSON value of [success]. - * - * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [SessionActResponse]. - * - * The following fields are required: - * ```java - * .actions() - * .message() - * .success() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionActResponse]. */ - class Builder internal constructor() { - - private var actions: JsonField>? = null - private var message: JsonField? = null - private var success: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(sessionActResponse: SessionActResponse) = apply { - actions = sessionActResponse.actions.map { it.toMutableList() } - message = sessionActResponse.message - success = sessionActResponse.success - additionalProperties = sessionActResponse.additionalProperties.toMutableMap() - } - - /** Actions that were executed */ - fun actions(actions: List) = actions(JsonField.of(actions)) - - /** - * Sets [Builder.actions] to an arbitrary JSON value. - * - * You should usually call [Builder.actions] with a well-typed `List` value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun actions(actions: JsonField>) = apply { - this.actions = actions.map { it.toMutableList() } - } - - /** - * Adds a single [Action] to [actions]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addAction(action: Action) = apply { - actions = - (actions ?: JsonField.of(mutableListOf())).also { - checkKnown("actions", it).add(action) - } - } - - /** Result message */ - fun message(message: String) = message(JsonField.of(message)) - - /** - * Sets [Builder.message] to an arbitrary JSON value. - * - * You should usually call [Builder.message] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun message(message: JsonField) = apply { this.message = message } - - /** Whether the action succeeded */ - fun success(success: Boolean) = success(JsonField.of(success)) - - /** - * Sets [Builder.success] to an arbitrary JSON value. - * - * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun success(success: JsonField) = apply { this.success = success } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [SessionActResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .actions() - * .message() - * .success() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): SessionActResponse = - SessionActResponse( - checkRequired("actions", actions).map { it.toImmutable() }, - checkRequired("message", message), - checkRequired("success", success), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): SessionActResponse = apply { - if (validated) { - return@apply - } - - actions().forEach { it.validate() } - message() - success() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + - (if (message.asKnown().isPresent) 1 else 0) + - (if (success.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionActResponse && - actions == other.actions && - message == other.message && - success == other.success && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(actions, message, success, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "SessionActResponse{actions=$actions, message=$message, success=$success, additionalProperties=$additionalProperties}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt deleted file mode 100644 index a3bb3fe..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ /dev/null @@ -1,229 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.core.toImmutable -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** Closes the browser and cleans up all resources associated with the session. */ -class SessionEndParams -private constructor( - private val sessionId: String?, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, - private val additionalBodyProperties: Map, -) : Params { - - fun sessionId(): Optional = Optional.ofNullable(sessionId) - - /** Additional body properties to send with the request. */ - fun _additionalBodyProperties(): Map = additionalBodyProperties - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - @JvmStatic fun none(): SessionEndParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionEndParams]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionEndParams]. */ - class Builder internal constructor() { - - private var sessionId: String? = null - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var additionalBodyProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(sessionEndParams: SessionEndParams) = apply { - sessionId = sessionEndParams.sessionId - additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionEndParams.additionalQueryParams.toBuilder() - additionalBodyProperties = sessionEndParams.additionalBodyProperties.toMutableMap() - } - - fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } - - /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ - fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - putAllAdditionalBodyProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - additionalBodyProperties.put(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { - additionalBodyProperties.remove(key) - } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalBodyProperty) - } - - /** - * Returns an immutable instance of [SessionEndParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionEndParams = - SessionEndParams( - sessionId, - additionalHeaders.build(), - additionalQueryParams.build(), - additionalBodyProperties.toImmutable(), - ) - } - - fun _body(): Optional> = - Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) - - fun _pathParam(index: Int): String = - when (index) { - 0 -> sessionId ?: "" - else -> "" - } - - override fun _headers(): Headers = additionalHeaders - - override fun _queryParams(): QueryParams = additionalQueryParams - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionEndParams && - sessionId == other.sessionId && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams && - additionalBodyProperties == other.additionalBodyProperties - } - - override fun hashCode(): Int = - Objects.hash(sessionId, additionalHeaders, additionalQueryParams, additionalBodyProperties) - - override fun toString() = - "SessionEndParams{sessionId=$sessionId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt deleted file mode 100644 index feba7d7..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt +++ /dev/null @@ -1,153 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional - -class SessionEndResponse -@JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor( - private val success: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of() - ) : this(success, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun success(): Optional = success.getOptional("success") - - /** - * Returns the raw JSON value of [success]. - * - * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [SessionEndResponse]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionEndResponse]. */ - class Builder internal constructor() { - - private var success: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(sessionEndResponse: SessionEndResponse) = apply { - success = sessionEndResponse.success - additionalProperties = sessionEndResponse.additionalProperties.toMutableMap() - } - - fun success(success: Boolean) = success(JsonField.of(success)) - - /** - * Sets [Builder.success] to an arbitrary JSON value. - * - * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun success(success: JsonField) = apply { this.success = success } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [SessionEndResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionEndResponse = - SessionEndResponse(success, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): SessionEndResponse = apply { - if (validated) { - return@apply - } - - success() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (success.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionEndResponse && - success == other.success && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(success, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "SessionEndResponse{success=$success, additionalProperties=$additionalProperties}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt deleted file mode 100644 index d2c5c47..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt +++ /dev/null @@ -1,1547 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.BaseDeserializer -import com.browserbase.api.core.BaseSerializer -import com.browserbase.api.core.Enum -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.allMaxBy -import com.browserbase.api.core.checkRequired -import com.browserbase.api.core.getOrThrow -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.ObjectCodec -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import com.fasterxml.jackson.databind.annotation.JsonSerialize -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.util.Collections -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** Runs an autonomous agent that can perform multiple actions to complete a complex task. */ -class SessionExecuteAgentParams -private constructor( - private val sessionId: String?, - private val xStreamResponse: XStreamResponse?, - private val body: Body, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun sessionId(): Optional = Optional.ofNullable(sessionId) - - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun agentConfig(): AgentConfig = body.agentConfig() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun executeOptions(): ExecuteOptions = body.executeOptions() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun frameId(): Optional = body.frameId() - - /** - * Returns the raw JSON value of [agentConfig]. - * - * Unlike [agentConfig], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _agentConfig(): JsonField = body._agentConfig() - - /** - * Returns the raw JSON value of [executeOptions]. - * - * Unlike [executeOptions], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _executeOptions(): JsonField = body._executeOptions() - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _frameId(): JsonField = body._frameId() - - fun _additionalBodyProperties(): Map = body._additionalProperties() - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [SessionExecuteAgentParams]. - * - * The following fields are required: - * ```java - * .agentConfig() - * .executeOptions() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionExecuteAgentParams]. */ - class Builder internal constructor() { - - private var sessionId: String? = null - private var xStreamResponse: XStreamResponse? = null - private var body: Body.Builder = Body.builder() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(sessionExecuteAgentParams: SessionExecuteAgentParams) = apply { - sessionId = sessionExecuteAgentParams.sessionId - xStreamResponse = sessionExecuteAgentParams.xStreamResponse - body = sessionExecuteAgentParams.body.toBuilder() - additionalHeaders = sessionExecuteAgentParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionExecuteAgentParams.additionalQueryParams.toBuilder() - } - - fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } - - /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ - fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) - - fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { - this.xStreamResponse = xStreamResponse - } - - /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = - xStreamResponse(xStreamResponse.getOrNull()) - - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [agentConfig] - * - [executeOptions] - * - [frameId] - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - fun agentConfig(agentConfig: AgentConfig) = apply { body.agentConfig(agentConfig) } - - /** - * Sets [Builder.agentConfig] to an arbitrary JSON value. - * - * You should usually call [Builder.agentConfig] with a well-typed [AgentConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun agentConfig(agentConfig: JsonField) = apply { - body.agentConfig(agentConfig) - } - - fun executeOptions(executeOptions: ExecuteOptions) = apply { - body.executeOptions(executeOptions) - } - - /** - * Sets [Builder.executeOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.executeOptions] with a well-typed [ExecuteOptions] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun executeOptions(executeOptions: JsonField) = apply { - body.executeOptions(executeOptions) - } - - fun frameId(frameId: String) = apply { body.frameId(frameId) } - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [SessionExecuteAgentParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .agentConfig() - * .executeOptions() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): SessionExecuteAgentParams = - SessionExecuteAgentParams( - sessionId, - xStreamResponse, - body.build(), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): Body = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> sessionId ?: "" - else -> "" - } - - override fun _headers(): Headers = - Headers.builder() - .apply { - xStreamResponse?.let { put("x-stream-response", it.toString()) } - putAll(additionalHeaders) - } - .build() - - override fun _queryParams(): QueryParams = additionalQueryParams - - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val agentConfig: JsonField, - private val executeOptions: JsonField, - private val frameId: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("agentConfig") - @ExcludeMissing - agentConfig: JsonField = JsonMissing.of(), - @JsonProperty("executeOptions") - @ExcludeMissing - executeOptions: JsonField = JsonMissing.of(), - @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), - ) : this(agentConfig, executeOptions, frameId, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun agentConfig(): AgentConfig = agentConfig.getRequired("agentConfig") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun executeOptions(): ExecuteOptions = executeOptions.getRequired("executeOptions") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun frameId(): Optional = frameId.getOptional("frameId") - - /** - * Returns the raw JSON value of [agentConfig]. - * - * Unlike [agentConfig], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("agentConfig") - @ExcludeMissing - fun _agentConfig(): JsonField = agentConfig - - /** - * Returns the raw JSON value of [executeOptions]. - * - * Unlike [executeOptions], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("executeOptions") - @ExcludeMissing - fun _executeOptions(): JsonField = executeOptions - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Body]. - * - * The following fields are required: - * ```java - * .agentConfig() - * .executeOptions() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var agentConfig: JsonField? = null - private var executeOptions: JsonField? = null - private var frameId: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - agentConfig = body.agentConfig - executeOptions = body.executeOptions - frameId = body.frameId - additionalProperties = body.additionalProperties.toMutableMap() - } - - fun agentConfig(agentConfig: AgentConfig) = agentConfig(JsonField.of(agentConfig)) - - /** - * Sets [Builder.agentConfig] to an arbitrary JSON value. - * - * You should usually call [Builder.agentConfig] with a well-typed [AgentConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun agentConfig(agentConfig: JsonField) = apply { - this.agentConfig = agentConfig - } - - fun executeOptions(executeOptions: ExecuteOptions) = - executeOptions(JsonField.of(executeOptions)) - - /** - * Sets [Builder.executeOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.executeOptions] with a well-typed [ExecuteOptions] - * value instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun executeOptions(executeOptions: JsonField) = apply { - this.executeOptions = executeOptions - } - - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun frameId(frameId: JsonField) = apply { this.frameId = frameId } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .agentConfig() - * .executeOptions() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Body = - Body( - checkRequired("agentConfig", agentConfig), - checkRequired("executeOptions", executeOptions), - frameId, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - agentConfig().validate() - executeOptions().validate() - frameId() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (agentConfig.asKnown().getOrNull()?.validity() ?: 0) + - (executeOptions.asKnown().getOrNull()?.validity() ?: 0) + - (if (frameId.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - agentConfig == other.agentConfig && - executeOptions == other.executeOptions && - frameId == other.frameId && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(agentConfig, executeOptions, frameId, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{agentConfig=$agentConfig, executeOptions=$executeOptions, frameId=$frameId, additionalProperties=$additionalProperties}" - } - - class AgentConfig - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val cua: JsonField, - private val model: JsonField, - private val provider: JsonField, - private val systemPrompt: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("provider") - @ExcludeMissing - provider: JsonField = JsonMissing.of(), - @JsonProperty("systemPrompt") - @ExcludeMissing - systemPrompt: JsonField = JsonMissing.of(), - ) : this(cua, model, provider, systemPrompt, mutableMapOf()) - - /** - * Enable Computer Use Agent mode - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun cua(): Optional = cua.getOptional("cua") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun model(): Optional = model.getOptional("model") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun provider(): Optional = provider.getOptional("provider") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") - - /** - * Returns the raw JSON value of [cua]. - * - * Unlike [cua], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("cua") @ExcludeMissing fun _cua(): JsonField = cua - - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - - /** - * Returns the raw JSON value of [provider]. - * - * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider - - /** - * Returns the raw JSON value of [systemPrompt]. - * - * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("systemPrompt") - @ExcludeMissing - fun _systemPrompt(): JsonField = systemPrompt - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [AgentConfig]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [AgentConfig]. */ - class Builder internal constructor() { - - private var cua: JsonField = JsonMissing.of() - private var model: JsonField = JsonMissing.of() - private var provider: JsonField = JsonMissing.of() - private var systemPrompt: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(agentConfig: AgentConfig) = apply { - cua = agentConfig.cua - model = agentConfig.model - provider = agentConfig.provider - systemPrompt = agentConfig.systemPrompt - additionalProperties = agentConfig.additionalProperties.toMutableMap() - } - - /** Enable Computer Use Agent mode */ - fun cua(cua: Boolean) = cua(JsonField.of(cua)) - - /** - * Sets [Builder.cua] to an arbitrary JSON value. - * - * You should usually call [Builder.cua] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun cua(cua: JsonField) = apply { this.cua = cua } - - fun model(model: Model) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [Model] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun model(model: JsonField) = apply { this.model = model } - - /** Alias for calling [model] with `Model.ofString(string)`. */ - fun model(string: String) = model(Model.ofString(string)) - - /** Alias for calling [model] with `Model.ofConfig(config)`. */ - fun model(config: ModelConfig) = model(Model.ofConfig(config)) - - fun provider(provider: Provider) = provider(JsonField.of(provider)) - - /** - * Sets [Builder.provider] to an arbitrary JSON value. - * - * You should usually call [Builder.provider] with a well-typed [Provider] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun provider(provider: JsonField) = apply { this.provider = provider } - - fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) - - /** - * Sets [Builder.systemPrompt] to an arbitrary JSON value. - * - * You should usually call [Builder.systemPrompt] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun systemPrompt(systemPrompt: JsonField) = apply { - this.systemPrompt = systemPrompt - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [AgentConfig]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): AgentConfig = - AgentConfig(cua, model, provider, systemPrompt, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): AgentConfig = apply { - if (validated) { - return@apply - } - - cua() - model().ifPresent { it.validate() } - provider().ifPresent { it.validate() } - systemPrompt() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (cua.asKnown().isPresent) 1 else 0) + - (model.asKnown().getOrNull()?.validity() ?: 0) + - (provider.asKnown().getOrNull()?.validity() ?: 0) + - (if (systemPrompt.asKnown().isPresent) 1 else 0) - - @JsonDeserialize(using = Model.Deserializer::class) - @JsonSerialize(using = Model.Serializer::class) - class Model - private constructor( - private val string: String? = null, - private val config: ModelConfig? = null, - private val _json: JsonValue? = null, - ) { - - fun string(): Optional = Optional.ofNullable(string) - - fun config(): Optional = Optional.ofNullable(config) - - fun isString(): Boolean = string != null - - fun isConfig(): Boolean = config != null - - fun asString(): String = string.getOrThrow("string") - - fun asConfig(): ModelConfig = config.getOrThrow("config") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - string != null -> visitor.visitString(string) - config != null -> visitor.visitConfig(config) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Model = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitString(string: String) {} - - override fun visitConfig(config: ModelConfig) { - config.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitString(string: String) = 1 - - override fun visitConfig(config: ModelConfig) = config.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Model && string == other.string && config == other.config - } - - override fun hashCode(): Int = Objects.hash(string, config) - - override fun toString(): String = - when { - string != null -> "Model{string=$string}" - config != null -> "Model{config=$config}" - _json != null -> "Model{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Model") - } - - companion object { - - @JvmStatic fun ofString(string: String) = Model(string = string) - - @JvmStatic fun ofConfig(config: ModelConfig) = Model(config = config) - } - - /** - * An interface that defines how to map each variant of [Model] to a value of type [T]. - */ - interface Visitor { - - fun visitString(string: String): T - - fun visitConfig(config: ModelConfig): T - - /** - * Maps an unknown variant of [Model] to a value of type [T]. - * - * An instance of [Model] can contain an unknown variant if it was deserialized from - * data that doesn't match any known variant. For example, if the SDK is on an older - * version than the API, then the API may respond with new variants that the SDK is - * unaware of. - * - * @throws StagehandInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown Model: $json") - } - } - - internal class Deserializer : BaseDeserializer(Model::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Model { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef())?.let { - Model(config = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Model(string = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible - // with all the possible variants (e.g. deserializing from array). - 0 -> Model(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the - // first completely valid match, or simply the first match if none are - // completely valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Model::class) { - - override fun serialize( - value: Model, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.config != null -> generator.writeObject(value.config) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Model") - } - } - } - } - - class Provider @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val OPENAI = of("openai") - - @JvmField val ANTHROPIC = of("anthropic") - - @JvmField val GOOGLE = of("google") - - @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) - } - - /** An enum containing [Provider]'s known values. */ - enum class Known { - OPENAI, - ANTHROPIC, - GOOGLE, - } - - /** - * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Provider] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if - * the SDK is on an older version than the API, then the API may respond with new - * members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - OPENAI, - ANTHROPIC, - GOOGLE, - /** - * An enum member indicating that [Provider] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you - * want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - OPENAI -> Value.OPENAI - ANTHROPIC -> Value.ANTHROPIC - GOOGLE -> Value.GOOGLE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - OPENAI -> Known.OPENAI - ANTHROPIC -> Known.ANTHROPIC - GOOGLE -> Known.GOOGLE - else -> throw StagehandInvalidDataException("Unknown Provider: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have - * the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Provider = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Provider && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is AgentConfig && - cua == other.cua && - model == other.model && - provider == other.provider && - systemPrompt == other.systemPrompt && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(cua, model, provider, systemPrompt, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "AgentConfig{cua=$cua, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" - } - - class ExecuteOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val instruction: JsonField, - private val highlightCursor: JsonField, - private val maxSteps: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("instruction") - @ExcludeMissing - instruction: JsonField = JsonMissing.of(), - @JsonProperty("highlightCursor") - @ExcludeMissing - highlightCursor: JsonField = JsonMissing.of(), - @JsonProperty("maxSteps") @ExcludeMissing maxSteps: JsonField = JsonMissing.of(), - ) : this(instruction, highlightCursor, maxSteps, mutableMapOf()) - - /** - * Task for the agent to complete - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun instruction(): String = instruction.getRequired("instruction") - - /** - * Visually highlight the cursor during actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun highlightCursor(): Optional = highlightCursor.getOptional("highlightCursor") - - /** - * Maximum number of steps the agent can take - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") - - /** - * Returns the raw JSON value of [instruction]. - * - * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("instruction") - @ExcludeMissing - fun _instruction(): JsonField = instruction - - /** - * Returns the raw JSON value of [highlightCursor]. - * - * Unlike [highlightCursor], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("highlightCursor") - @ExcludeMissing - fun _highlightCursor(): JsonField = highlightCursor - - /** - * Returns the raw JSON value of [maxSteps]. - * - * Unlike [maxSteps], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("maxSteps") @ExcludeMissing fun _maxSteps(): JsonField = maxSteps - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ExecuteOptions]. - * - * The following fields are required: - * ```java - * .instruction() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ExecuteOptions]. */ - class Builder internal constructor() { - - private var instruction: JsonField? = null - private var highlightCursor: JsonField = JsonMissing.of() - private var maxSteps: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(executeOptions: ExecuteOptions) = apply { - instruction = executeOptions.instruction - highlightCursor = executeOptions.highlightCursor - maxSteps = executeOptions.maxSteps - additionalProperties = executeOptions.additionalProperties.toMutableMap() - } - - /** Task for the agent to complete */ - fun instruction(instruction: String) = instruction(JsonField.of(instruction)) - - /** - * Sets [Builder.instruction] to an arbitrary JSON value. - * - * You should usually call [Builder.instruction] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun instruction(instruction: JsonField) = apply { - this.instruction = instruction - } - - /** Visually highlight the cursor during actions */ - fun highlightCursor(highlightCursor: Boolean) = - highlightCursor(JsonField.of(highlightCursor)) - - /** - * Sets [Builder.highlightCursor] to an arbitrary JSON value. - * - * You should usually call [Builder.highlightCursor] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun highlightCursor(highlightCursor: JsonField) = apply { - this.highlightCursor = highlightCursor - } - - /** Maximum number of steps the agent can take */ - fun maxSteps(maxSteps: Long) = maxSteps(JsonField.of(maxSteps)) - - /** - * Sets [Builder.maxSteps] to an arbitrary JSON value. - * - * You should usually call [Builder.maxSteps] with a well-typed [Long] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun maxSteps(maxSteps: JsonField) = apply { this.maxSteps = maxSteps } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [ExecuteOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .instruction() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ExecuteOptions = - ExecuteOptions( - checkRequired("instruction", instruction), - highlightCursor, - maxSteps, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): ExecuteOptions = apply { - if (validated) { - return@apply - } - - instruction() - highlightCursor() - maxSteps() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (instruction.asKnown().isPresent) 1 else 0) + - (if (highlightCursor.asKnown().isPresent) 1 else 0) + - (if (maxSteps.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ExecuteOptions && - instruction == other.instruction && - highlightCursor == other.highlightCursor && - maxSteps == other.maxSteps && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(instruction, highlightCursor, maxSteps, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" - } - - class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of("true") - - @JvmField val FALSE = of("false") - - @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) - } - - /** An enum containing [XStreamResponse]'s known values. */ - enum class Known { - TRUE, - FALSE, - } - - /** - * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - FALSE, - /** - * An enum member indicating that [XStreamResponse] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - FALSE -> Value.FALSE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XStreamResponse = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XStreamResponse && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionExecuteAgentParams && - sessionId == other.sessionId && - xStreamResponse == other.xStreamResponse && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "SessionExecuteAgentParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt deleted file mode 100644 index 3c3af1d..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt +++ /dev/null @@ -1,158 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional - -class SessionExecuteAgentResponse -@JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor( - private val message: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of() - ) : this(message, mutableMapOf()) - - /** - * Final message from the agent - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun message(): Optional = message.getOptional("message") - - /** - * Returns the raw JSON value of [message]. - * - * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [SessionExecuteAgentResponse]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionExecuteAgentResponse]. */ - class Builder internal constructor() { - - private var message: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(sessionExecuteAgentResponse: SessionExecuteAgentResponse) = apply { - message = sessionExecuteAgentResponse.message - additionalProperties = sessionExecuteAgentResponse.additionalProperties.toMutableMap() - } - - /** Final message from the agent */ - fun message(message: String) = message(JsonField.of(message)) - - /** - * Sets [Builder.message] to an arbitrary JSON value. - * - * You should usually call [Builder.message] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun message(message: JsonField) = apply { this.message = message } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [SessionExecuteAgentResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionExecuteAgentResponse = - SessionExecuteAgentResponse(message, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): SessionExecuteAgentResponse = apply { - if (validated) { - return@apply - } - - message() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (message.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionExecuteAgentResponse && - message == other.message && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(message, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "SessionExecuteAgentResponse{message=$message, additionalProperties=$additionalProperties}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt deleted file mode 100644 index 3833673..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ /dev/null @@ -1,1064 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.Enum -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** - * Extracts data from the current page using natural language instructions and optional JSON schema - * for structured output. - */ -class SessionExtractParams -private constructor( - private val sessionId: String?, - private val xStreamResponse: XStreamResponse?, - private val body: Body, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun sessionId(): Optional = Optional.ofNullable(sessionId) - - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - - /** - * Frame ID to extract from - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun frameId(): Optional = body.frameId() - - /** - * Natural language instruction for extraction - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun instruction(): Optional = body.instruction() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun options(): Optional = body.options() - - /** - * JSON Schema for structured output - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun schema(): Optional = body.schema() - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _frameId(): JsonField = body._frameId() - - /** - * Returns the raw JSON value of [instruction]. - * - * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _instruction(): JsonField = body._instruction() - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _options(): JsonField = body._options() - - /** - * Returns the raw JSON value of [schema]. - * - * Unlike [schema], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _schema(): JsonField = body._schema() - - fun _additionalBodyProperties(): Map = body._additionalProperties() - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - @JvmStatic fun none(): SessionExtractParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionExtractParams]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionExtractParams]. */ - class Builder internal constructor() { - - private var sessionId: String? = null - private var xStreamResponse: XStreamResponse? = null - private var body: Body.Builder = Body.builder() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(sessionExtractParams: SessionExtractParams) = apply { - sessionId = sessionExtractParams.sessionId - xStreamResponse = sessionExtractParams.xStreamResponse - body = sessionExtractParams.body.toBuilder() - additionalHeaders = sessionExtractParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionExtractParams.additionalQueryParams.toBuilder() - } - - fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } - - /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ - fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) - - fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { - this.xStreamResponse = xStreamResponse - } - - /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = - xStreamResponse(xStreamResponse.getOrNull()) - - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [frameId] - * - [instruction] - * - [options] - * - [schema] - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - /** Frame ID to extract from */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } - - /** Natural language instruction for extraction */ - fun instruction(instruction: String) = apply { body.instruction(instruction) } - - /** - * Sets [Builder.instruction] to an arbitrary JSON value. - * - * You should usually call [Builder.instruction] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun instruction(instruction: JsonField) = apply { body.instruction(instruction) } - - fun options(options: Options) = apply { body.options(options) } - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun options(options: JsonField) = apply { body.options(options) } - - /** JSON Schema for structured output */ - fun schema(schema: Schema) = apply { body.schema(schema) } - - /** - * Sets [Builder.schema] to an arbitrary JSON value. - * - * You should usually call [Builder.schema] with a well-typed [Schema] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun schema(schema: JsonField) = apply { body.schema(schema) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [SessionExtractParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionExtractParams = - SessionExtractParams( - sessionId, - xStreamResponse, - body.build(), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): Body = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> sessionId ?: "" - else -> "" - } - - override fun _headers(): Headers = - Headers.builder() - .apply { - xStreamResponse?.let { put("x-stream-response", it.toString()) } - putAll(additionalHeaders) - } - .build() - - override fun _queryParams(): QueryParams = additionalQueryParams - - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val frameId: JsonField, - private val instruction: JsonField, - private val options: JsonField, - private val schema: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), - @JsonProperty("instruction") - @ExcludeMissing - instruction: JsonField = JsonMissing.of(), - @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), - @JsonProperty("schema") @ExcludeMissing schema: JsonField = JsonMissing.of(), - ) : this(frameId, instruction, options, schema, mutableMapOf()) - - /** - * Frame ID to extract from - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun frameId(): Optional = frameId.getOptional("frameId") - - /** - * Natural language instruction for extraction - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun instruction(): Optional = instruction.getOptional("instruction") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun options(): Optional = options.getOptional("options") - - /** - * JSON Schema for structured output - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun schema(): Optional = schema.getOptional("schema") - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId - - /** - * Returns the raw JSON value of [instruction]. - * - * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("instruction") - @ExcludeMissing - fun _instruction(): JsonField = instruction - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options - - /** - * Returns the raw JSON value of [schema]. - * - * Unlike [schema], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("schema") @ExcludeMissing fun _schema(): JsonField = schema - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Body]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var frameId: JsonField = JsonMissing.of() - private var instruction: JsonField = JsonMissing.of() - private var options: JsonField = JsonMissing.of() - private var schema: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - frameId = body.frameId - instruction = body.instruction - options = body.options - schema = body.schema - additionalProperties = body.additionalProperties.toMutableMap() - } - - /** Frame ID to extract from */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun frameId(frameId: JsonField) = apply { this.frameId = frameId } - - /** Natural language instruction for extraction */ - fun instruction(instruction: String) = instruction(JsonField.of(instruction)) - - /** - * Sets [Builder.instruction] to an arbitrary JSON value. - * - * You should usually call [Builder.instruction] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun instruction(instruction: JsonField) = apply { - this.instruction = instruction - } - - fun options(options: Options) = options(JsonField.of(options)) - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun options(options: JsonField) = apply { this.options = options } - - /** JSON Schema for structured output */ - fun schema(schema: Schema) = schema(JsonField.of(schema)) - - /** - * Sets [Builder.schema] to an arbitrary JSON value. - * - * You should usually call [Builder.schema] with a well-typed [Schema] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun schema(schema: JsonField) = apply { this.schema = schema } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Body = - Body(frameId, instruction, options, schema, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - frameId() - instruction() - options().ifPresent { it.validate() } - schema().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (frameId.asKnown().isPresent) 1 else 0) + - (if (instruction.asKnown().isPresent) 1 else 0) + - (options.asKnown().getOrNull()?.validity() ?: 0) + - (schema.asKnown().getOrNull()?.validity() ?: 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - frameId == other.frameId && - instruction == other.instruction && - options == other.options && - schema == other.schema && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(frameId, instruction, options, schema, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{frameId=$frameId, instruction=$instruction, options=$options, schema=$schema, additionalProperties=$additionalProperties}" - } - - class Options - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val model: JsonField, - private val selector: JsonField, - private val timeout: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("selector") - @ExcludeMissing - selector: JsonField = JsonMissing.of(), - @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), - ) : this(model, selector, timeout, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun model(): Optional = model.getOptional("model") - - /** - * Extract only from elements matching this selector - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun selector(): Optional = selector.getOptional("selector") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun timeout(): Optional = timeout.getOptional("timeout") - - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - - /** - * Returns the raw JSON value of [selector]. - * - * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector - - /** - * Returns the raw JSON value of [timeout]. - * - * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Options]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Options]. */ - class Builder internal constructor() { - - private var model: JsonField = JsonMissing.of() - private var selector: JsonField = JsonMissing.of() - private var timeout: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(options: Options) = apply { - model = options.model - selector = options.selector - timeout = options.timeout - additionalProperties = options.additionalProperties.toMutableMap() - } - - fun model(model: ModelConfig) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - - /** Extract only from elements matching this selector */ - fun selector(selector: String) = selector(JsonField.of(selector)) - - /** - * Sets [Builder.selector] to an arbitrary JSON value. - * - * You should usually call [Builder.selector] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun selector(selector: JsonField) = apply { this.selector = selector } - - fun timeout(timeout: Long) = timeout(JsonField.of(timeout)) - - /** - * Sets [Builder.timeout] to an arbitrary JSON value. - * - * You should usually call [Builder.timeout] with a well-typed [Long] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun timeout(timeout: JsonField) = apply { this.timeout = timeout } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Options]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Options = - Options(model, selector, timeout, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Options = apply { - if (validated) { - return@apply - } - - model().ifPresent { it.validate() } - selector() - timeout() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (model.asKnown().getOrNull()?.validity() ?: 0) + - (if (selector.asKnown().isPresent) 1 else 0) + - (if (timeout.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Options && - model == other.model && - selector == other.selector && - timeout == other.timeout && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(model, selector, timeout, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" - } - - /** JSON Schema for structured output */ - class Schema - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Schema]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Schema]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(schema: Schema) = apply { - additionalProperties = schema.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Schema]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Schema = Schema(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Schema = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Schema && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Schema{additionalProperties=$additionalProperties}" - } - - class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of("true") - - @JvmField val FALSE = of("false") - - @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) - } - - /** An enum containing [XStreamResponse]'s known values. */ - enum class Known { - TRUE, - FALSE, - } - - /** - * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - FALSE, - /** - * An enum member indicating that [XStreamResponse] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - FALSE -> Value.FALSE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XStreamResponse = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XStreamResponse && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionExtractParams && - sessionId == other.sessionId && - xStreamResponse == other.xStreamResponse && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "SessionExtractParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt deleted file mode 100644 index 6816259..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ /dev/null @@ -1,457 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.BaseDeserializer -import com.browserbase.api.core.BaseSerializer -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.allMaxBy -import com.browserbase.api.core.getOrThrow -import com.browserbase.api.core.toImmutable -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.ObjectCodec -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import com.fasterxml.jackson.databind.annotation.JsonSerialize -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.util.Collections -import java.util.Objects -import java.util.Optional - -/** Default extraction result */ -@JsonDeserialize(using = SessionExtractResponse.Deserializer::class) -@JsonSerialize(using = SessionExtractResponse.Serializer::class) -class SessionExtractResponse -private constructor( - private val extraction: Extraction? = null, - private val custom: Custom? = null, - private val _json: JsonValue? = null, -) { - - /** Default extraction result */ - fun extraction(): Optional = Optional.ofNullable(extraction) - - /** Structured data matching provided schema */ - fun custom(): Optional = Optional.ofNullable(custom) - - fun isExtraction(): Boolean = extraction != null - - fun isCustom(): Boolean = custom != null - - /** Default extraction result */ - fun asExtraction(): Extraction = extraction.getOrThrow("extraction") - - /** Structured data matching provided schema */ - fun asCustom(): Custom = custom.getOrThrow("custom") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - extraction != null -> visitor.visitExtraction(extraction) - custom != null -> visitor.visitCustom(custom) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): SessionExtractResponse = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitExtraction(extraction: Extraction) { - extraction.validate() - } - - override fun visitCustom(custom: Custom) { - custom.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitExtraction(extraction: Extraction) = extraction.validity() - - override fun visitCustom(custom: Custom) = custom.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionExtractResponse && - extraction == other.extraction && - custom == other.custom - } - - override fun hashCode(): Int = Objects.hash(extraction, custom) - - override fun toString(): String = - when { - extraction != null -> "SessionExtractResponse{extraction=$extraction}" - custom != null -> "SessionExtractResponse{custom=$custom}" - _json != null -> "SessionExtractResponse{_unknown=$_json}" - else -> throw IllegalStateException("Invalid SessionExtractResponse") - } - - companion object { - - /** Default extraction result */ - @JvmStatic - fun ofExtraction(extraction: Extraction) = SessionExtractResponse(extraction = extraction) - - /** Structured data matching provided schema */ - @JvmStatic fun ofCustom(custom: Custom) = SessionExtractResponse(custom = custom) - } - - /** - * An interface that defines how to map each variant of [SessionExtractResponse] to a value of - * type [T]. - */ - interface Visitor { - - /** Default extraction result */ - fun visitExtraction(extraction: Extraction): T - - /** Structured data matching provided schema */ - fun visitCustom(custom: Custom): T - - /** - * Maps an unknown variant of [SessionExtractResponse] to a value of type [T]. - * - * An instance of [SessionExtractResponse] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, if the SDK is - * on an older version than the API, then the API may respond with new variants that the SDK - * is unaware of. - * - * @throws StagehandInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown SessionExtractResponse: $json") - } - } - - internal class Deserializer : - BaseDeserializer(SessionExtractResponse::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): SessionExtractResponse { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef())?.let { - SessionExtractResponse(extraction = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - SessionExtractResponse(custom = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible with all - // the possible variants (e.g. deserializing from boolean). - 0 -> SessionExtractResponse(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the first - // completely valid match, or simply the first match if none are completely valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : - BaseSerializer(SessionExtractResponse::class) { - - override fun serialize( - value: SessionExtractResponse, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.extraction != null -> generator.writeObject(value.extraction) - value.custom != null -> generator.writeObject(value.custom) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid SessionExtractResponse") - } - } - } - - /** Default extraction result */ - class Extraction - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val extraction: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("extraction") - @ExcludeMissing - extraction: JsonField = JsonMissing.of() - ) : this(extraction, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun extraction(): Optional = extraction.getOptional("extraction") - - /** - * Returns the raw JSON value of [extraction]. - * - * Unlike [extraction], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("extraction") - @ExcludeMissing - fun _extraction(): JsonField = extraction - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Extraction]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Extraction]. */ - class Builder internal constructor() { - - private var extraction: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(extraction: Extraction) = apply { - this.extraction = extraction.extraction - additionalProperties = extraction.additionalProperties.toMutableMap() - } - - fun extraction(extraction: String) = extraction(JsonField.of(extraction)) - - /** - * Sets [Builder.extraction] to an arbitrary JSON value. - * - * You should usually call [Builder.extraction] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun extraction(extraction: JsonField) = apply { this.extraction = extraction } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Extraction]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Extraction = Extraction(extraction, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Extraction = apply { - if (validated) { - return@apply - } - - extraction() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (extraction.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Extraction && - extraction == other.extraction && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(extraction, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Extraction{extraction=$extraction, additionalProperties=$additionalProperties}" - } - - /** Structured data matching provided schema */ - class Custom - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Custom]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Custom]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(custom: Custom) = apply { - additionalProperties = custom.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Custom]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Custom = Custom(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Custom = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Custom && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Custom{additionalProperties=$additionalProperties}" - } -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt deleted file mode 100644 index e57efd3..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ /dev/null @@ -1,992 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.Enum -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.checkRequired -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** Navigates the browser to the specified URL and waits for page load. */ -class SessionNavigateParams -private constructor( - private val sessionId: String?, - private val xStreamResponse: XStreamResponse?, - private val body: Body, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun sessionId(): Optional = Optional.ofNullable(sessionId) - - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - - /** - * URL to navigate to - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun url(): String = body.url() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun frameId(): Optional = body.frameId() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun options(): Optional = body.options() - - /** - * Returns the raw JSON value of [url]. - * - * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _url(): JsonField = body._url() - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _frameId(): JsonField = body._frameId() - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _options(): JsonField = body._options() - - fun _additionalBodyProperties(): Map = body._additionalProperties() - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [SessionNavigateParams]. - * - * The following fields are required: - * ```java - * .url() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionNavigateParams]. */ - class Builder internal constructor() { - - private var sessionId: String? = null - private var xStreamResponse: XStreamResponse? = null - private var body: Body.Builder = Body.builder() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(sessionNavigateParams: SessionNavigateParams) = apply { - sessionId = sessionNavigateParams.sessionId - xStreamResponse = sessionNavigateParams.xStreamResponse - body = sessionNavigateParams.body.toBuilder() - additionalHeaders = sessionNavigateParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionNavigateParams.additionalQueryParams.toBuilder() - } - - fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } - - /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ - fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) - - fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { - this.xStreamResponse = xStreamResponse - } - - /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = - xStreamResponse(xStreamResponse.getOrNull()) - - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [url] - * - [frameId] - * - [options] - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - /** URL to navigate to */ - fun url(url: String) = apply { body.url(url) } - - /** - * Sets [Builder.url] to an arbitrary JSON value. - * - * You should usually call [Builder.url] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun url(url: JsonField) = apply { body.url(url) } - - fun frameId(frameId: String) = apply { body.frameId(frameId) } - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } - - fun options(options: Options) = apply { body.options(options) } - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun options(options: JsonField) = apply { body.options(options) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [SessionNavigateParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .url() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): SessionNavigateParams = - SessionNavigateParams( - sessionId, - xStreamResponse, - body.build(), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): Body = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> sessionId ?: "" - else -> "" - } - - override fun _headers(): Headers = - Headers.builder() - .apply { - xStreamResponse?.let { put("x-stream-response", it.toString()) } - putAll(additionalHeaders) - } - .build() - - override fun _queryParams(): QueryParams = additionalQueryParams - - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val url: JsonField, - private val frameId: JsonField, - private val options: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), - @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), - @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), - ) : this(url, frameId, options, mutableMapOf()) - - /** - * URL to navigate to - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun url(): String = url.getRequired("url") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun frameId(): Optional = frameId.getOptional("frameId") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun options(): Optional = options.getOptional("options") - - /** - * Returns the raw JSON value of [url]. - * - * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Body]. - * - * The following fields are required: - * ```java - * .url() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var url: JsonField? = null - private var frameId: JsonField = JsonMissing.of() - private var options: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - url = body.url - frameId = body.frameId - options = body.options - additionalProperties = body.additionalProperties.toMutableMap() - } - - /** URL to navigate to */ - fun url(url: String) = url(JsonField.of(url)) - - /** - * Sets [Builder.url] to an arbitrary JSON value. - * - * You should usually call [Builder.url] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun url(url: JsonField) = apply { this.url = url } - - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun frameId(frameId: JsonField) = apply { this.frameId = frameId } - - fun options(options: Options) = options(JsonField.of(options)) - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun options(options: JsonField) = apply { this.options = options } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .url() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Body = - Body( - checkRequired("url", url), - frameId, - options, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - url() - frameId() - options().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (url.asKnown().isPresent) 1 else 0) + - (if (frameId.asKnown().isPresent) 1 else 0) + - (options.asKnown().getOrNull()?.validity() ?: 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - url == other.url && - frameId == other.frameId && - options == other.options && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(url, frameId, options, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{url=$url, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" - } - - class Options - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val waitUntil: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("waitUntil") - @ExcludeMissing - waitUntil: JsonField = JsonMissing.of() - ) : this(waitUntil, mutableMapOf()) - - /** - * When to consider navigation complete - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun waitUntil(): Optional = waitUntil.getOptional("waitUntil") - - /** - * Returns the raw JSON value of [waitUntil]. - * - * Unlike [waitUntil], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("waitUntil") - @ExcludeMissing - fun _waitUntil(): JsonField = waitUntil - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Options]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Options]. */ - class Builder internal constructor() { - - private var waitUntil: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(options: Options) = apply { - waitUntil = options.waitUntil - additionalProperties = options.additionalProperties.toMutableMap() - } - - /** When to consider navigation complete */ - fun waitUntil(waitUntil: WaitUntil) = waitUntil(JsonField.of(waitUntil)) - - /** - * Sets [Builder.waitUntil] to an arbitrary JSON value. - * - * You should usually call [Builder.waitUntil] with a well-typed [WaitUntil] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun waitUntil(waitUntil: JsonField) = apply { this.waitUntil = waitUntil } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Options]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Options = Options(waitUntil, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Options = apply { - if (validated) { - return@apply - } - - waitUntil().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (waitUntil.asKnown().getOrNull()?.validity() ?: 0) - - /** When to consider navigation complete */ - class WaitUntil @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val LOAD = of("load") - - @JvmField val DOMCONTENTLOADED = of("domcontentloaded") - - @JvmField val NETWORKIDLE = of("networkidle") - - @JvmStatic fun of(value: String) = WaitUntil(JsonField.of(value)) - } - - /** An enum containing [WaitUntil]'s known values. */ - enum class Known { - LOAD, - DOMCONTENTLOADED, - NETWORKIDLE, - } - - /** - * An enum containing [WaitUntil]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [WaitUntil] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if - * the SDK is on an older version than the API, then the API may respond with new - * members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - LOAD, - DOMCONTENTLOADED, - NETWORKIDLE, - /** - * An enum member indicating that [WaitUntil] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you - * want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - LOAD -> Value.LOAD - DOMCONTENTLOADED -> Value.DOMCONTENTLOADED - NETWORKIDLE -> Value.NETWORKIDLE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - LOAD -> Known.LOAD - DOMCONTENTLOADED -> Known.DOMCONTENTLOADED - NETWORKIDLE -> Known.NETWORKIDLE - else -> throw StagehandInvalidDataException("Unknown WaitUntil: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have - * the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): WaitUntil = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is WaitUntil && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Options && - waitUntil == other.waitUntil && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(waitUntil, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Options{waitUntil=$waitUntil, additionalProperties=$additionalProperties}" - } - - class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of("true") - - @JvmField val FALSE = of("false") - - @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) - } - - /** An enum containing [XStreamResponse]'s known values. */ - enum class Known { - TRUE, - FALSE, - } - - /** - * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - FALSE, - /** - * An enum member indicating that [XStreamResponse] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - FALSE -> Value.FALSE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XStreamResponse = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XStreamResponse && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionNavigateParams && - sessionId == other.sessionId && - xStreamResponse == other.xStreamResponse && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "SessionNavigateParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt deleted file mode 100644 index 50422bd..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt +++ /dev/null @@ -1,216 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional - -/** Navigation response (may be null) */ -class SessionNavigateResponse -@JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor( - private val ok: JsonField, - private val status: JsonField, - private val url: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("ok") @ExcludeMissing ok: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), - @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), - ) : this(ok, status, url, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun ok(): Optional = ok.getOptional("ok") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun status(): Optional = status.getOptional("status") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun url(): Optional = url.getOptional("url") - - /** - * Returns the raw JSON value of [ok]. - * - * Unlike [ok], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("ok") @ExcludeMissing fun _ok(): JsonField = ok - - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - - /** - * Returns the raw JSON value of [url]. - * - * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [SessionNavigateResponse]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionNavigateResponse]. */ - class Builder internal constructor() { - - private var ok: JsonField = JsonMissing.of() - private var status: JsonField = JsonMissing.of() - private var url: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(sessionNavigateResponse: SessionNavigateResponse) = apply { - ok = sessionNavigateResponse.ok - status = sessionNavigateResponse.status - url = sessionNavigateResponse.url - additionalProperties = sessionNavigateResponse.additionalProperties.toMutableMap() - } - - fun ok(ok: Boolean) = ok(JsonField.of(ok)) - - /** - * Sets [Builder.ok] to an arbitrary JSON value. - * - * You should usually call [Builder.ok] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun ok(ok: JsonField) = apply { this.ok = ok } - - fun status(status: Long) = status(JsonField.of(status)) - - /** - * Sets [Builder.status] to an arbitrary JSON value. - * - * You should usually call [Builder.status] with a well-typed [Long] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun status(status: JsonField) = apply { this.status = status } - - fun url(url: String) = url(JsonField.of(url)) - - /** - * Sets [Builder.url] to an arbitrary JSON value. - * - * You should usually call [Builder.url] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun url(url: JsonField) = apply { this.url = url } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [SessionNavigateResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionNavigateResponse = - SessionNavigateResponse(ok, status, url, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): SessionNavigateResponse = apply { - if (validated) { - return@apply - } - - ok() - status() - url() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (ok.asKnown().isPresent) 1 else 0) + - (if (status.asKnown().isPresent) 1 else 0) + - (if (url.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionNavigateResponse && - ok == other.ok && - status == other.status && - url == other.url && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(ok, status, url, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "SessionNavigateResponse{ok=$ok, status=$status, url=$url, additionalProperties=$additionalProperties}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt deleted file mode 100644 index 0d67973..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ /dev/null @@ -1,902 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.Enum -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** - * Returns a list of candidate actions that can be performed on the page, optionally filtered by - * natural language instruction. - */ -class SessionObserveParams -private constructor( - private val sessionId: String?, - private val xStreamResponse: XStreamResponse?, - private val body: Body, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun sessionId(): Optional = Optional.ofNullable(sessionId) - - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - - /** - * Frame ID to observe - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun frameId(): Optional = body.frameId() - - /** - * Natural language instruction to filter actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun instruction(): Optional = body.instruction() - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun options(): Optional = body.options() - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _frameId(): JsonField = body._frameId() - - /** - * Returns the raw JSON value of [instruction]. - * - * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _instruction(): JsonField = body._instruction() - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _options(): JsonField = body._options() - - fun _additionalBodyProperties(): Map = body._additionalProperties() - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - @JvmStatic fun none(): SessionObserveParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionObserveParams]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionObserveParams]. */ - class Builder internal constructor() { - - private var sessionId: String? = null - private var xStreamResponse: XStreamResponse? = null - private var body: Body.Builder = Body.builder() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(sessionObserveParams: SessionObserveParams) = apply { - sessionId = sessionObserveParams.sessionId - xStreamResponse = sessionObserveParams.xStreamResponse - body = sessionObserveParams.body.toBuilder() - additionalHeaders = sessionObserveParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionObserveParams.additionalQueryParams.toBuilder() - } - - fun sessionId(sessionId: String?) = apply { this.sessionId = sessionId } - - /** Alias for calling [Builder.sessionId] with `sessionId.orElse(null)`. */ - fun sessionId(sessionId: Optional) = sessionId(sessionId.getOrNull()) - - fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { - this.xStreamResponse = xStreamResponse - } - - /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = - xStreamResponse(xStreamResponse.getOrNull()) - - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [frameId] - * - [instruction] - * - [options] - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - /** Frame ID to observe */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } - - /** Natural language instruction to filter actions */ - fun instruction(instruction: String) = apply { body.instruction(instruction) } - - /** - * Sets [Builder.instruction] to an arbitrary JSON value. - * - * You should usually call [Builder.instruction] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun instruction(instruction: JsonField) = apply { body.instruction(instruction) } - - fun options(options: Options) = apply { body.options(options) } - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun options(options: JsonField) = apply { body.options(options) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [SessionObserveParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionObserveParams = - SessionObserveParams( - sessionId, - xStreamResponse, - body.build(), - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): Body = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> sessionId ?: "" - else -> "" - } - - override fun _headers(): Headers = - Headers.builder() - .apply { - xStreamResponse?.let { put("x-stream-response", it.toString()) } - putAll(additionalHeaders) - } - .build() - - override fun _queryParams(): QueryParams = additionalQueryParams - - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val frameId: JsonField, - private val instruction: JsonField, - private val options: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), - @JsonProperty("instruction") - @ExcludeMissing - instruction: JsonField = JsonMissing.of(), - @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), - ) : this(frameId, instruction, options, mutableMapOf()) - - /** - * Frame ID to observe - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun frameId(): Optional = frameId.getOptional("frameId") - - /** - * Natural language instruction to filter actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun instruction(): Optional = instruction.getOptional("instruction") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun options(): Optional = options.getOptional("options") - - /** - * Returns the raw JSON value of [frameId]. - * - * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId - - /** - * Returns the raw JSON value of [instruction]. - * - * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("instruction") - @ExcludeMissing - fun _instruction(): JsonField = instruction - - /** - * Returns the raw JSON value of [options]. - * - * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Body]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var frameId: JsonField = JsonMissing.of() - private var instruction: JsonField = JsonMissing.of() - private var options: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - frameId = body.frameId - instruction = body.instruction - options = body.options - additionalProperties = body.additionalProperties.toMutableMap() - } - - /** Frame ID to observe */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) - - /** - * Sets [Builder.frameId] to an arbitrary JSON value. - * - * You should usually call [Builder.frameId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun frameId(frameId: JsonField) = apply { this.frameId = frameId } - - /** Natural language instruction to filter actions */ - fun instruction(instruction: String) = instruction(JsonField.of(instruction)) - - /** - * Sets [Builder.instruction] to an arbitrary JSON value. - * - * You should usually call [Builder.instruction] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun instruction(instruction: JsonField) = apply { - this.instruction = instruction - } - - fun options(options: Options) = options(JsonField.of(options)) - - /** - * Sets [Builder.options] to an arbitrary JSON value. - * - * You should usually call [Builder.options] with a well-typed [Options] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun options(options: JsonField) = apply { this.options = options } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Body = - Body(frameId, instruction, options, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - frameId() - instruction() - options().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (frameId.asKnown().isPresent) 1 else 0) + - (if (instruction.asKnown().isPresent) 1 else 0) + - (options.asKnown().getOrNull()?.validity() ?: 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - frameId == other.frameId && - instruction == other.instruction && - options == other.options && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(frameId, instruction, options, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{frameId=$frameId, instruction=$instruction, options=$options, additionalProperties=$additionalProperties}" - } - - class Options - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val model: JsonField, - private val selector: JsonField, - private val timeout: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("selector") - @ExcludeMissing - selector: JsonField = JsonMissing.of(), - @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), - ) : this(model, selector, timeout, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun model(): Optional = model.getOptional("model") - - /** - * Observe only elements matching this selector - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun selector(): Optional = selector.getOptional("selector") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun timeout(): Optional = timeout.getOptional("timeout") - - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - - /** - * Returns the raw JSON value of [selector]. - * - * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector - - /** - * Returns the raw JSON value of [timeout]. - * - * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Options]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Options]. */ - class Builder internal constructor() { - - private var model: JsonField = JsonMissing.of() - private var selector: JsonField = JsonMissing.of() - private var timeout: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(options: Options) = apply { - model = options.model - selector = options.selector - timeout = options.timeout - additionalProperties = options.additionalProperties.toMutableMap() - } - - fun model(model: ModelConfig) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - - /** Observe only elements matching this selector */ - fun selector(selector: String) = selector(JsonField.of(selector)) - - /** - * Sets [Builder.selector] to an arbitrary JSON value. - * - * You should usually call [Builder.selector] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun selector(selector: JsonField) = apply { this.selector = selector } - - fun timeout(timeout: Long) = timeout(JsonField.of(timeout)) - - /** - * Sets [Builder.timeout] to an arbitrary JSON value. - * - * You should usually call [Builder.timeout] with a well-typed [Long] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun timeout(timeout: JsonField) = apply { this.timeout = timeout } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Options]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Options = - Options(model, selector, timeout, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Options = apply { - if (validated) { - return@apply - } - - model().ifPresent { it.validate() } - selector() - timeout() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (model.asKnown().getOrNull()?.validity() ?: 0) + - (if (selector.asKnown().isPresent) 1 else 0) + - (if (timeout.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Options && - model == other.model && - selector == other.selector && - timeout == other.timeout && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(model, selector, timeout, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" - } - - class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of("true") - - @JvmField val FALSE = of("false") - - @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) - } - - /** An enum containing [XStreamResponse]'s known values. */ - enum class Known { - TRUE, - FALSE, - } - - /** - * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - FALSE, - /** - * An enum member indicating that [XStreamResponse] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - FALSE -> Value.FALSE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - FALSE -> Known.FALSE - else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XStreamResponse = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XStreamResponse && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionObserveParams && - sessionId == other.sessionId && - xStreamResponse == other.xStreamResponse && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash(sessionId, xStreamResponse, body, additionalHeaders, additionalQueryParams) - - override fun toString() = - "SessionObserveParams{sessionId=$sessionId, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index cda3e99..e0c55aa 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -2,143 +2,39 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params -import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** - * Initializes a new Stagehand session with a browser instance. Returns a session ID that must be - * used for all subsequent requests. + * Creates a new browser session with the specified configuration. Returns a session ID used for all + * subsequent operations. */ class SessionStartParams private constructor( - private val body: Body, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val body: JsonValue, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - /** - * API key for Browserbase Cloud - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun browserbaseApiKey(): String = body.browserbaseApiKey() - - /** - * Project ID for Browserbase - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun browserbaseProjectId(): String = body.browserbaseProjectId() - - /** - * Timeout in ms to wait for DOM to settle - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun domSettleTimeout(): Optional = body.domSettleTimeout() - - /** - * AI model to use for actions (must be prefixed with provider/) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun model(): Optional = body.model() - - /** - * Enable self-healing for failed actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun selfHeal(): Optional = body.selfHeal() - - /** - * Custom system prompt for AI actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun systemPrompt(): Optional = body.systemPrompt() - - /** - * Logging verbosity level - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun verbose(): Optional = body.verbose() - - /** - * Returns the raw JSON value of [browserbaseApiKey]. - * - * Unlike [browserbaseApiKey], this method doesn't throw if the JSON field has an unexpected - * type. - */ - fun _browserbaseApiKey(): JsonField = body._browserbaseApiKey() - - /** - * Returns the raw JSON value of [browserbaseProjectId]. - * - * Unlike [browserbaseProjectId], this method doesn't throw if the JSON field has an unexpected - * type. - */ - fun _browserbaseProjectId(): JsonField = body._browserbaseProjectId() - - /** - * Returns the raw JSON value of [domSettleTimeout]. - * - * Unlike [domSettleTimeout], this method doesn't throw if the JSON field has an unexpected - * type. - */ - fun _domSettleTimeout(): JsonField = body._domSettleTimeout() - - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _model(): JsonField = body._model() - - /** - * Returns the raw JSON value of [selfHeal]. - * - * Unlike [selfHeal], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _selfHeal(): JsonField = body._selfHeal() - - /** - * Returns the raw JSON value of [systemPrompt]. - * - * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _systemPrompt(): JsonField = body._systemPrompt() - - /** - * Returns the raw JSON value of [verbose]. - * - * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _verbose(): JsonField = body._verbose() - - fun _additionalBodyProperties(): Map = body._additionalProperties() + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + fun body(): JsonValue = body /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -150,160 +46,58 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [SessionStartParams]. - * - * The following fields are required: - * ```java - * .browserbaseApiKey() - * .browserbaseProjectId() - * ``` - */ + @JvmStatic fun none(): SessionStartParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionStartParams]. */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionStartParams]. */ class Builder internal constructor() { - private var body: Body.Builder = Body.builder() + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var body: JsonValue = JsonMissing.of() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @JvmSynthetic internal fun from(sessionStartParams: SessionStartParams) = apply { - body = sessionStartParams.body.toBuilder() + xLanguage = sessionStartParams.xLanguage + xSdkVersion = sessionStartParams.xSdkVersion + xSentAt = sessionStartParams.xSentAt + xStreamResponse = sessionStartParams.xStreamResponse + body = sessionStartParams.body additionalHeaders = sessionStartParams.additionalHeaders.toBuilder() additionalQueryParams = sessionStartParams.additionalQueryParams.toBuilder() } - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [browserbaseApiKey] - * - [browserbaseProjectId] - * - [domSettleTimeout] - * - [model] - * - [selfHeal] - * - etc. - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } - /** API key for Browserbase Cloud */ - fun browserbaseApiKey(browserbaseApiKey: String) = apply { - body.browserbaseApiKey(browserbaseApiKey) - } + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - /** - * Sets [Builder.browserbaseApiKey] to an arbitrary JSON value. - * - * You should usually call [Builder.browserbaseApiKey] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun browserbaseApiKey(browserbaseApiKey: JsonField) = apply { - body.browserbaseApiKey(browserbaseApiKey) - } + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } - /** Project ID for Browserbase */ - fun browserbaseProjectId(browserbaseProjectId: String) = apply { - body.browserbaseProjectId(browserbaseProjectId) - } + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** - * Sets [Builder.browserbaseProjectId] to an arbitrary JSON value. - * - * You should usually call [Builder.browserbaseProjectId] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun browserbaseProjectId(browserbaseProjectId: JsonField) = apply { - body.browserbaseProjectId(browserbaseProjectId) - } + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } - /** Timeout in ms to wait for DOM to settle */ - fun domSettleTimeout(domSettleTimeout: Long) = apply { - body.domSettleTimeout(domSettleTimeout) - } + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** - * Sets [Builder.domSettleTimeout] to an arbitrary JSON value. - * - * You should usually call [Builder.domSettleTimeout] with a well-typed [Long] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun domSettleTimeout(domSettleTimeout: JsonField) = apply { - body.domSettleTimeout(domSettleTimeout) + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse } - /** AI model to use for actions (must be prefixed with provider/) */ - fun model(model: String) = apply { body.model(model) } - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun model(model: JsonField) = apply { body.model(model) } - - /** Enable self-healing for failed actions */ - fun selfHeal(selfHeal: Boolean) = apply { body.selfHeal(selfHeal) } - - /** - * Sets [Builder.selfHeal] to an arbitrary JSON value. - * - * You should usually call [Builder.selfHeal] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun selfHeal(selfHeal: JsonField) = apply { body.selfHeal(selfHeal) } - - /** Custom system prompt for AI actions */ - fun systemPrompt(systemPrompt: String) = apply { body.systemPrompt(systemPrompt) } - - /** - * Sets [Builder.systemPrompt] to an arbitrary JSON value. - * - * You should usually call [Builder.systemPrompt] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun systemPrompt(systemPrompt: JsonField) = apply { - body.systemPrompt(systemPrompt) - } + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) - /** Logging verbosity level */ - fun verbose(verbose: Long) = apply { body.verbose(verbose) } - - /** - * Sets [Builder.verbose] to an arbitrary JSON value. - * - * You should usually call [Builder.verbose] with a well-typed [Long] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } + fun body(body: JsonValue) = apply { this.body = body } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -407,469 +201,51 @@ private constructor( * Returns an immutable instance of [SessionStartParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .browserbaseApiKey() - * .browserbaseProjectId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): SessionStartParams = SessionStartParams( - body.build(), + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): Body = body + fun _body(): JsonValue = body - override fun _headers(): Headers = additionalHeaders + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() override fun _queryParams(): QueryParams = additionalQueryParams - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val browserbaseApiKey: JsonField, - private val browserbaseProjectId: JsonField, - private val domSettleTimeout: JsonField, - private val model: JsonField, - private val selfHeal: JsonField, - private val systemPrompt: JsonField, - private val verbose: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("BROWSERBASE_API_KEY") - @ExcludeMissing - browserbaseApiKey: JsonField = JsonMissing.of(), - @JsonProperty("BROWSERBASE_PROJECT_ID") - @ExcludeMissing - browserbaseProjectId: JsonField = JsonMissing.of(), - @JsonProperty("domSettleTimeout") - @ExcludeMissing - domSettleTimeout: JsonField = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), - @JsonProperty("selfHeal") - @ExcludeMissing - selfHeal: JsonField = JsonMissing.of(), - @JsonProperty("systemPrompt") - @ExcludeMissing - systemPrompt: JsonField = JsonMissing.of(), - @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), - ) : this( - browserbaseApiKey, - browserbaseProjectId, - domSettleTimeout, - model, - selfHeal, - systemPrompt, - verbose, - mutableMapOf(), - ) - - /** - * API key for Browserbase Cloud - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun browserbaseApiKey(): String = browserbaseApiKey.getRequired("BROWSERBASE_API_KEY") - - /** - * Project ID for Browserbase - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun browserbaseProjectId(): String = - browserbaseProjectId.getRequired("BROWSERBASE_PROJECT_ID") - - /** - * Timeout in ms to wait for DOM to settle - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun domSettleTimeout(): Optional = domSettleTimeout.getOptional("domSettleTimeout") - - /** - * AI model to use for actions (must be prefixed with provider/) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun model(): Optional = model.getOptional("model") - - /** - * Enable self-healing for failed actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun selfHeal(): Optional = selfHeal.getOptional("selfHeal") - - /** - * Custom system prompt for AI actions - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") - - /** - * Logging verbosity level - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun verbose(): Optional = verbose.getOptional("verbose") - - /** - * Returns the raw JSON value of [browserbaseApiKey]. - * - * Unlike [browserbaseApiKey], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("BROWSERBASE_API_KEY") - @ExcludeMissing - fun _browserbaseApiKey(): JsonField = browserbaseApiKey - - /** - * Returns the raw JSON value of [browserbaseProjectId]. - * - * Unlike [browserbaseProjectId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("BROWSERBASE_PROJECT_ID") - @ExcludeMissing - fun _browserbaseProjectId(): JsonField = browserbaseProjectId - - /** - * Returns the raw JSON value of [domSettleTimeout]. - * - * Unlike [domSettleTimeout], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("domSettleTimeout") - @ExcludeMissing - fun _domSettleTimeout(): JsonField = domSettleTimeout - - /** - * Returns the raw JSON value of [model]. - * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - - /** - * Returns the raw JSON value of [selfHeal]. - * - * Unlike [selfHeal], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("selfHeal") @ExcludeMissing fun _selfHeal(): JsonField = selfHeal - - /** - * Returns the raw JSON value of [systemPrompt]. - * - * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("systemPrompt") - @ExcludeMissing - fun _systemPrompt(): JsonField = systemPrompt - - /** - * Returns the raw JSON value of [verbose]. - * - * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Body]. - * - * The following fields are required: - * ```java - * .browserbaseApiKey() - * .browserbaseProjectId() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var browserbaseApiKey: JsonField? = null - private var browserbaseProjectId: JsonField? = null - private var domSettleTimeout: JsonField = JsonMissing.of() - private var model: JsonField = JsonMissing.of() - private var selfHeal: JsonField = JsonMissing.of() - private var systemPrompt: JsonField = JsonMissing.of() - private var verbose: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - browserbaseApiKey = body.browserbaseApiKey - browserbaseProjectId = body.browserbaseProjectId - domSettleTimeout = body.domSettleTimeout - model = body.model - selfHeal = body.selfHeal - systemPrompt = body.systemPrompt - verbose = body.verbose - additionalProperties = body.additionalProperties.toMutableMap() - } - - /** API key for Browserbase Cloud */ - fun browserbaseApiKey(browserbaseApiKey: String) = - browserbaseApiKey(JsonField.of(browserbaseApiKey)) - - /** - * Sets [Builder.browserbaseApiKey] to an arbitrary JSON value. - * - * You should usually call [Builder.browserbaseApiKey] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun browserbaseApiKey(browserbaseApiKey: JsonField) = apply { - this.browserbaseApiKey = browserbaseApiKey - } - - /** Project ID for Browserbase */ - fun browserbaseProjectId(browserbaseProjectId: String) = - browserbaseProjectId(JsonField.of(browserbaseProjectId)) - - /** - * Sets [Builder.browserbaseProjectId] to an arbitrary JSON value. - * - * You should usually call [Builder.browserbaseProjectId] with a well-typed [String] - * value instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun browserbaseProjectId(browserbaseProjectId: JsonField) = apply { - this.browserbaseProjectId = browserbaseProjectId - } - - /** Timeout in ms to wait for DOM to settle */ - fun domSettleTimeout(domSettleTimeout: Long) = - domSettleTimeout(JsonField.of(domSettleTimeout)) - - /** - * Sets [Builder.domSettleTimeout] to an arbitrary JSON value. - * - * You should usually call [Builder.domSettleTimeout] with a well-typed [Long] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun domSettleTimeout(domSettleTimeout: JsonField) = apply { - this.domSettleTimeout = domSettleTimeout - } - - /** AI model to use for actions (must be prefixed with provider/) */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - - /** Enable self-healing for failed actions */ - fun selfHeal(selfHeal: Boolean) = selfHeal(JsonField.of(selfHeal)) - - /** - * Sets [Builder.selfHeal] to an arbitrary JSON value. - * - * You should usually call [Builder.selfHeal] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun selfHeal(selfHeal: JsonField) = apply { this.selfHeal = selfHeal } - - /** Custom system prompt for AI actions */ - fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) - - /** - * Sets [Builder.systemPrompt] to an arbitrary JSON value. - * - * You should usually call [Builder.systemPrompt] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun systemPrompt(systemPrompt: JsonField) = apply { - this.systemPrompt = systemPrompt - } - - /** Logging verbosity level */ - fun verbose(verbose: Long) = verbose(JsonField.of(verbose)) - - /** - * Sets [Builder.verbose] to an arbitrary JSON value. - * - * You should usually call [Builder.verbose] with a well-typed [Long] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun verbose(verbose: JsonField) = apply { this.verbose = verbose } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .browserbaseApiKey() - * .browserbaseProjectId() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Body = - Body( - checkRequired("browserbaseApiKey", browserbaseApiKey), - checkRequired("browserbaseProjectId", browserbaseProjectId), - domSettleTimeout, - model, - selfHeal, - systemPrompt, - verbose, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - browserbaseApiKey() - browserbaseProjectId() - domSettleTimeout() - model() - selfHeal() - systemPrompt() - verbose() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (browserbaseApiKey.asKnown().isPresent) 1 else 0) + - (if (browserbaseProjectId.asKnown().isPresent) 1 else 0) + - (if (domSettleTimeout.asKnown().isPresent) 1 else 0) + - (if (model.asKnown().isPresent) 1 else 0) + - (if (selfHeal.asKnown().isPresent) 1 else 0) + - (if (systemPrompt.asKnown().isPresent) 1 else 0) + - (if (verbose.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - browserbaseApiKey == other.browserbaseApiKey && - browserbaseProjectId == other.browserbaseProjectId && - domSettleTimeout == other.domSettleTimeout && - model == other.model && - selfHeal == other.selfHeal && - systemPrompt == other.systemPrompt && - verbose == other.verbose && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - browserbaseApiKey, - browserbaseProjectId, - domSettleTimeout, - model, - selfHeal, - systemPrompt, - verbose, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{browserbaseApiKey=$browserbaseApiKey, browserbaseProjectId=$browserbaseProjectId, domSettleTimeout=$domSettleTimeout, model=$model, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, additionalProperties=$additionalProperties}" - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } return other is SessionStartParams && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams } - override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams) + override fun hashCode(): Int = + Objects.hash( + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) override fun toString() = - "SessionStartParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionStartParams{xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index 2e71372..b63f41e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -3,61 +3,19 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects class SessionStartResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor( - private val available: JsonField, - private val sessionId: JsonField, - private val additionalProperties: MutableMap, -) { - - @JsonCreator - private constructor( - @JsonProperty("available") @ExcludeMissing available: JsonField = JsonMissing.of(), - @JsonProperty("sessionId") @ExcludeMissing sessionId: JsonField = JsonMissing.of(), - ) : this(available, sessionId, mutableMapOf()) +private constructor(private val additionalProperties: MutableMap) { - /** - * Whether the session is ready to use - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun available(): Boolean = available.getRequired("available") - - /** - * Unique identifier for the session - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun sessionId(): String = sessionId.getRequired("sessionId") - - /** - * Returns the raw JSON value of [available]. - * - * Unlike [available], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("available") @ExcludeMissing fun _available(): JsonField = available - - /** - * Returns the raw JSON value of [sessionId]. - * - * Unlike [sessionId], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("sessionId") @ExcludeMissing fun _sessionId(): JsonField = sessionId + @JsonCreator private constructor() : this(mutableMapOf()) @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -73,56 +31,20 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [SessionStartResponse]. - * - * The following fields are required: - * ```java - * .available() - * .sessionId() - * ``` - */ + /** Returns a mutable builder for constructing an instance of [SessionStartResponse]. */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionStartResponse]. */ class Builder internal constructor() { - private var available: JsonField? = null - private var sessionId: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionStartResponse: SessionStartResponse) = apply { - available = sessionStartResponse.available - sessionId = sessionStartResponse.sessionId additionalProperties = sessionStartResponse.additionalProperties.toMutableMap() } - /** Whether the session is ready to use */ - fun available(available: Boolean) = available(JsonField.of(available)) - - /** - * Sets [Builder.available] to an arbitrary JSON value. - * - * You should usually call [Builder.available] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun available(available: JsonField) = apply { this.available = available } - - /** Unique identifier for the session */ - fun sessionId(sessionId: String) = sessionId(JsonField.of(sessionId)) - - /** - * Sets [Builder.sessionId] to an arbitrary JSON value. - * - * You should usually call [Builder.sessionId] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun sessionId(sessionId: JsonField) = apply { this.sessionId = sessionId } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -146,21 +68,9 @@ private constructor( * Returns an immutable instance of [SessionStartResponse]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .available() - * .sessionId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): SessionStartResponse = - SessionStartResponse( - checkRequired("available", available), - checkRequired("sessionId", sessionId), - additionalProperties.toMutableMap(), - ) + SessionStartResponse(additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -170,8 +80,6 @@ private constructor( return@apply } - available() - sessionId() validated = true } @@ -188,26 +96,19 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic - internal fun validity(): Int = - (if (available.asKnown().isPresent) 1 else 0) + - (if (sessionId.asKnown().isPresent) 1 else 0) + @JvmSynthetic internal fun validity(): Int = 0 override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is SessionStartResponse && - available == other.available && - sessionId == other.sessionId && - additionalProperties == other.additionalProperties + return other is SessionStartResponse && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(available, sessionId, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = - "SessionStartResponse{available=$available, sessionId=$sessionId, additionalProperties=$additionalProperties}" + override fun toString() = "SessionStartResponse{additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index 5c78924..d481fec 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -5,21 +5,8 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor -import com.browserbase.api.models.sessions.Action -import com.browserbase.api.models.sessions.SessionActParams -import com.browserbase.api.models.sessions.SessionActResponse -import com.browserbase.api.models.sessions.SessionEndParams -import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse -import com.browserbase.api.models.sessions.SessionExtractParams -import com.browserbase.api.models.sessions.SessionExtractResponse -import com.browserbase.api.models.sessions.SessionNavigateParams -import com.browserbase.api.models.sessions.SessionNavigateResponse -import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse -import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.function.Consumer @@ -38,207 +25,26 @@ interface SessionServiceAsync { fun withOptions(modifier: Consumer): SessionServiceAsync /** - * Performs a browser action based on natural language instruction or a specific action object - * returned by observe(). + * Creates a new browser session with the specified configuration. Returns a session ID used for + * all subsequent operations. */ - fun act(sessionId: String, params: SessionActParams): CompletableFuture = - act(sessionId, params, RequestOptions.none()) - - /** @see act */ - fun act( - sessionId: String, - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - act(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see act */ - fun act(params: SessionActParams): CompletableFuture = - act(params, RequestOptions.none()) - - /** @see act */ - fun act( - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** Closes the browser and cleans up all resources associated with the session. */ - fun end(sessionId: String): CompletableFuture = - end(sessionId, SessionEndParams.none()) - - /** @see end */ - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - end(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see end */ - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - ): CompletableFuture = end(sessionId, params, RequestOptions.none()) - - /** @see end */ - fun end( - params: SessionEndParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** @see end */ - fun end(params: SessionEndParams): CompletableFuture = - end(params, RequestOptions.none()) - - /** @see end */ - fun end( - sessionId: String, - requestOptions: RequestOptions, - ): CompletableFuture = - end(sessionId, SessionEndParams.none(), requestOptions) - - /** Runs an autonomous agent that can perform multiple actions to complete a complex task. */ - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - ): CompletableFuture = - executeAgent(sessionId, params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams - ): CompletableFuture = executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** - * Extracts data from the current page using natural language instructions and optional JSON - * schema for structured output. - */ - fun extract(sessionId: String): CompletableFuture = - extract(sessionId, SessionExtractParams.none()) - - /** @see extract */ - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see extract */ - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - ): CompletableFuture = extract(sessionId, params, RequestOptions.none()) - - /** @see extract */ - fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture - - /** @see extract */ - fun extract(params: SessionExtractParams): CompletableFuture = - extract(params, RequestOptions.none()) - - /** @see extract */ - fun extract( - sessionId: String, - requestOptions: RequestOptions, - ): CompletableFuture = - extract(sessionId, SessionExtractParams.none(), requestOptions) - - /** Navigates the browser to the specified URL and waits for page load. */ - fun navigate( - sessionId: String, - params: SessionNavigateParams, - ): CompletableFuture> = - navigate(sessionId, params, RequestOptions.none()) - - /** @see navigate */ - fun navigate( - sessionId: String, - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see navigate */ - fun navigate( - params: SessionNavigateParams - ): CompletableFuture> = - navigate(params, RequestOptions.none()) - - /** @see navigate */ - fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** - * Returns a list of candidate actions that can be performed on the page, optionally filtered by - * natural language instruction. - */ - fun observe(sessionId: String): CompletableFuture> = - observe(sessionId, SessionObserveParams.none()) - - /** @see observe */ - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see observe */ - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - ): CompletableFuture> = observe(sessionId, params, RequestOptions.none()) - - /** @see observe */ - fun observe( - params: SessionObserveParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** @see observe */ - fun observe(params: SessionObserveParams): CompletableFuture> = - observe(params, RequestOptions.none()) - - /** @see observe */ - fun observe( - sessionId: String, - requestOptions: RequestOptions, - ): CompletableFuture> = - observe(sessionId, SessionObserveParams.none(), requestOptions) - - /** - * Initializes a new Stagehand session with a browser instance. Returns a session ID that must - * be used for all subsequent requests. - */ - fun start(params: SessionStartParams): CompletableFuture = - start(params, RequestOptions.none()) + fun start(): CompletableFuture = start(SessionStartParams.none()) /** @see start */ fun start( - params: SessionStartParams, + params: SessionStartParams = SessionStartParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see start */ + fun start( + params: SessionStartParams = SessionStartParams.none() + ): CompletableFuture = start(params, RequestOptions.none()) + + /** @see start */ + fun start(requestOptions: RequestOptions): CompletableFuture = + start(SessionStartParams.none(), requestOptions) + /** * A view of [SessionServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -254,226 +60,28 @@ interface SessionServiceAsync { ): SessionServiceAsync.WithRawResponse /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/act`, but is otherwise the - * same as [SessionServiceAsync.act]. - */ - fun act( - sessionId: String, - params: SessionActParams, - ): CompletableFuture> = - act(sessionId, params, RequestOptions.none()) - - /** @see act */ - fun act( - sessionId: String, - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - act(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see act */ - fun act(params: SessionActParams): CompletableFuture> = - act(params, RequestOptions.none()) - - /** @see act */ - fun act( - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/end`, but is otherwise the - * same as [SessionServiceAsync.end]. - */ - fun end(sessionId: String): CompletableFuture> = - end(sessionId, SessionEndParams.none()) - - /** @see end */ - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - end(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see end */ - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - ): CompletableFuture> = - end(sessionId, params, RequestOptions.none()) - - /** @see end */ - fun end( - params: SessionEndParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** @see end */ - fun end(params: SessionEndParams): CompletableFuture> = - end(params, RequestOptions.none()) - - /** @see end */ - fun end( - sessionId: String, - requestOptions: RequestOptions, - ): CompletableFuture> = - end(sessionId, SessionEndParams.none(), requestOptions) - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/agentExecute`, but is - * otherwise the same as [SessionServiceAsync.executeAgent]. - */ - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - ): CompletableFuture> = - executeAgent(sessionId, params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams - ): CompletableFuture> = - executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/extract`, but is otherwise - * the same as [SessionServiceAsync.extract]. - */ - fun extract(sessionId: String): CompletableFuture> = - extract(sessionId, SessionExtractParams.none()) - - /** @see extract */ - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see extract */ - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - ): CompletableFuture> = - extract(sessionId, params, RequestOptions.none()) - - /** @see extract */ - fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** @see extract */ - fun extract( - params: SessionExtractParams - ): CompletableFuture> = - extract(params, RequestOptions.none()) - - /** @see extract */ - fun extract( - sessionId: String, - requestOptions: RequestOptions, - ): CompletableFuture> = - extract(sessionId, SessionExtractParams.none(), requestOptions) - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/navigate`, but is otherwise - * the same as [SessionServiceAsync.navigate]. - */ - fun navigate( - sessionId: String, - params: SessionNavigateParams, - ): CompletableFuture>> = - navigate(sessionId, params, RequestOptions.none()) - - /** @see navigate */ - fun navigate( - sessionId: String, - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture>> = - navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see navigate */ - fun navigate( - params: SessionNavigateParams - ): CompletableFuture>> = - navigate(params, RequestOptions.none()) - - /** @see navigate */ - fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture>> - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/observe`, but is otherwise - * the same as [SessionServiceAsync.observe]. + * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as + * [SessionServiceAsync.start]. */ - fun observe(sessionId: String): CompletableFuture>> = - observe(sessionId, SessionObserveParams.none()) - - /** @see observe */ - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture>> = - observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) + fun start(): CompletableFuture> = + start(SessionStartParams.none()) - /** @see observe */ - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - ): CompletableFuture>> = - observe(sessionId, params, RequestOptions.none()) - - /** @see observe */ - fun observe( - params: SessionObserveParams, + /** @see start */ + fun start( + params: SessionStartParams = SessionStartParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture>> - - /** @see observe */ - fun observe( - params: SessionObserveParams - ): CompletableFuture>> = observe(params, RequestOptions.none()) - - /** @see observe */ - fun observe( - sessionId: String, - requestOptions: RequestOptions, - ): CompletableFuture>> = - observe(sessionId, SessionObserveParams.none(), requestOptions) + ): CompletableFuture> - /** - * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as - * [SessionServiceAsync.start]. - */ + /** @see start */ fun start( - params: SessionStartParams + params: SessionStartParams = SessionStartParams.none() ): CompletableFuture> = start(params, RequestOptions.none()) /** @see start */ fun start( - params: SessionStartParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + requestOptions: RequestOptions + ): CompletableFuture> = + start(SessionStartParams.none(), requestOptions) } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index baa7114..056c59c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -4,7 +4,6 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions -import com.browserbase.api.core.checkRequired import com.browserbase.api.core.handlers.errorBodyHandler import com.browserbase.api.core.handlers.errorHandler import com.browserbase.api.core.handlers.jsonHandler @@ -16,24 +15,10 @@ import com.browserbase.api.core.http.HttpResponseFor import com.browserbase.api.core.http.json import com.browserbase.api.core.http.parseable import com.browserbase.api.core.prepareAsync -import com.browserbase.api.models.sessions.Action -import com.browserbase.api.models.sessions.SessionActParams -import com.browserbase.api.models.sessions.SessionActResponse -import com.browserbase.api.models.sessions.SessionEndParams -import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse -import com.browserbase.api.models.sessions.SessionExtractParams -import com.browserbase.api.models.sessions.SessionExtractResponse -import com.browserbase.api.models.sessions.SessionNavigateParams -import com.browserbase.api.models.sessions.SessionNavigateResponse -import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse -import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.function.Consumer -import kotlin.jvm.optionals.getOrNull class SessionServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : SessionServiceAsync { @@ -47,48 +32,6 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl override fun withOptions(modifier: Consumer): SessionServiceAsync = SessionServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - override fun act( - params: SessionActParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // post /sessions/{sessionId}/act - withRawResponse().act(params, requestOptions).thenApply { it.parse() } - - override fun end( - params: SessionEndParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // post /sessions/{sessionId}/end - withRawResponse().end(params, requestOptions).thenApply { it.parse() } - - override fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // post /sessions/{sessionId}/agentExecute - withRawResponse().executeAgent(params, requestOptions).thenApply { it.parse() } - - override fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions, - ): CompletableFuture = - // post /sessions/{sessionId}/extract - withRawResponse().extract(params, requestOptions).thenApply { it.parse() } - - override fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions, - ): CompletableFuture> = - // post /sessions/{sessionId}/navigate - withRawResponse().navigate(params, requestOptions).thenApply { it.parse() } - - override fun observe( - params: SessionObserveParams, - requestOptions: RequestOptions, - ): CompletableFuture> = - // post /sessions/{sessionId}/observe - withRawResponse().observe(params, requestOptions).thenApply { it.parse() } - override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -109,210 +52,6 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl clientOptions.toBuilder().apply(modifier::accept).build() ) - private val actHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun act( - params: SessionActParams, - requestOptions: RequestOptions, - ): CompletableFuture> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "act") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { actHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - } - - private val endHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun end( - params: SessionEndParams, - requestOptions: RequestOptions, - ): CompletableFuture> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "end") - .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { endHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - } - - private val executeAgentHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions, - ): CompletableFuture> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "agentExecute") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { executeAgentHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - } - - private val extractHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions, - ): CompletableFuture> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "extract") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { extractHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - } - - private val navigateHandler: Handler> = - jsonHandler>(clientOptions.jsonMapper) - - override fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions, - ): CompletableFuture>> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "navigate") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { navigateHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.ifPresent { it.validate() } - } - } - } - } - } - - private val observeHandler: Handler> = - jsonHandler>(clientOptions.jsonMapper) - - override fun observe( - params: SessionObserveParams, - requestOptions: RequestOptions, - ): CompletableFuture>> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "observe") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepareAsync(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - return request - .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } - .thenApply { response -> - errorHandler.handle(response).parseable { - response - .use { observeHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.forEach { it.validate() } - } - } - } - } - } - private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index aac24dc..ddd7ad3 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -5,22 +5,9 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor -import com.browserbase.api.models.sessions.Action -import com.browserbase.api.models.sessions.SessionActParams -import com.browserbase.api.models.sessions.SessionActResponse -import com.browserbase.api.models.sessions.SessionEndParams -import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse -import com.browserbase.api.models.sessions.SessionExtractParams -import com.browserbase.api.models.sessions.SessionExtractResponse -import com.browserbase.api.models.sessions.SessionNavigateParams -import com.browserbase.api.models.sessions.SessionNavigateResponse -import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import com.google.errorprone.annotations.MustBeClosed -import java.util.Optional import java.util.function.Consumer interface SessionService { @@ -38,184 +25,24 @@ interface SessionService { fun withOptions(modifier: Consumer): SessionService /** - * Performs a browser action based on natural language instruction or a specific action object - * returned by observe(). + * Creates a new browser session with the specified configuration. Returns a session ID used for + * all subsequent operations. */ - fun act(sessionId: String, params: SessionActParams): SessionActResponse = - act(sessionId, params, RequestOptions.none()) + fun start(): SessionStartResponse = start(SessionStartParams.none()) - /** @see act */ - fun act( - sessionId: String, - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionActResponse = act(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see act */ - fun act(params: SessionActParams): SessionActResponse = act(params, RequestOptions.none()) - - /** @see act */ - fun act( - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionActResponse - - /** Closes the browser and cleans up all resources associated with the session. */ - fun end(sessionId: String): SessionEndResponse = end(sessionId, SessionEndParams.none()) - - /** @see end */ - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionEndResponse = end(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see end */ - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - ): SessionEndResponse = end(sessionId, params, RequestOptions.none()) - - /** @see end */ - fun end( - params: SessionEndParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionEndResponse - - /** @see end */ - fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) - - /** @see end */ - fun end(sessionId: String, requestOptions: RequestOptions): SessionEndResponse = - end(sessionId, SessionEndParams.none(), requestOptions) - - /** Runs an autonomous agent that can perform multiple actions to complete a complex task. */ - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - ): SessionExecuteAgentResponse = executeAgent(sessionId, params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionExecuteAgentResponse = - executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see executeAgent */ - fun executeAgent(params: SessionExecuteAgentParams): SessionExecuteAgentResponse = - executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionExecuteAgentResponse - - /** - * Extracts data from the current page using natural language instructions and optional JSON - * schema for structured output. - */ - fun extract(sessionId: String): SessionExtractResponse = - extract(sessionId, SessionExtractParams.none()) - - /** @see extract */ - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionExtractResponse = - extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see extract */ - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - ): SessionExtractResponse = extract(sessionId, params, RequestOptions.none()) - - /** @see extract */ - fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionExtractResponse - - /** @see extract */ - fun extract(params: SessionExtractParams): SessionExtractResponse = - extract(params, RequestOptions.none()) - - /** @see extract */ - fun extract(sessionId: String, requestOptions: RequestOptions): SessionExtractResponse = - extract(sessionId, SessionExtractParams.none(), requestOptions) - - /** Navigates the browser to the specified URL and waits for page load. */ - fun navigate( - sessionId: String, - params: SessionNavigateParams, - ): Optional = navigate(sessionId, params, RequestOptions.none()) - - /** @see navigate */ - fun navigate( - sessionId: String, - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): Optional = - navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see navigate */ - fun navigate(params: SessionNavigateParams): Optional = - navigate(params, RequestOptions.none()) - - /** @see navigate */ - fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): Optional - - /** - * Returns a list of candidate actions that can be performed on the page, optionally filtered by - * natural language instruction. - */ - fun observe(sessionId: String): List = observe(sessionId, SessionObserveParams.none()) - - /** @see observe */ - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): List = observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see observe */ - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - ): List = observe(sessionId, params, RequestOptions.none()) - - /** @see observe */ - fun observe( - params: SessionObserveParams, + /** @see start */ + fun start( + params: SessionStartParams = SessionStartParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): List - - /** @see observe */ - fun observe(params: SessionObserveParams): List = observe(params, RequestOptions.none()) - - /** @see observe */ - fun observe(sessionId: String, requestOptions: RequestOptions): List = - observe(sessionId, SessionObserveParams.none(), requestOptions) + ): SessionStartResponse - /** - * Initializes a new Stagehand session with a browser instance. Returns a session ID that must - * be used for all subsequent requests. - */ - fun start(params: SessionStartParams): SessionStartResponse = + /** @see start */ + fun start(params: SessionStartParams = SessionStartParams.none()): SessionStartResponse = start(params, RequestOptions.none()) /** @see start */ - fun start( - params: SessionStartParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): SessionStartResponse + fun start(requestOptions: RequestOptions): SessionStartResponse = + start(SessionStartParams.none(), requestOptions) /** A view of [SessionService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -227,249 +54,29 @@ interface SessionService { */ fun withOptions(modifier: Consumer): SessionService.WithRawResponse - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/act`, but is otherwise the - * same as [SessionService.act]. - */ - @MustBeClosed - fun act(sessionId: String, params: SessionActParams): HttpResponseFor = - act(sessionId, params, RequestOptions.none()) - - /** @see act */ - @MustBeClosed - fun act( - sessionId: String, - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - act(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see act */ - @MustBeClosed - fun act(params: SessionActParams): HttpResponseFor = - act(params, RequestOptions.none()) - - /** @see act */ - @MustBeClosed - fun act( - params: SessionActParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/end`, but is otherwise the - * same as [SessionService.end]. - */ - @MustBeClosed - fun end(sessionId: String): HttpResponseFor = - end(sessionId, SessionEndParams.none()) - - /** @see end */ - @MustBeClosed - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - end(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see end */ - @MustBeClosed - fun end( - sessionId: String, - params: SessionEndParams = SessionEndParams.none(), - ): HttpResponseFor = end(sessionId, params, RequestOptions.none()) - - /** @see end */ - @MustBeClosed - fun end( - params: SessionEndParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor - - /** @see end */ - @MustBeClosed - fun end(params: SessionEndParams): HttpResponseFor = - end(params, RequestOptions.none()) - - /** @see end */ - @MustBeClosed - fun end( - sessionId: String, - requestOptions: RequestOptions, - ): HttpResponseFor = - end(sessionId, SessionEndParams.none(), requestOptions) - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/agentExecute`, but is - * otherwise the same as [SessionService.executeAgent]. - */ - @MustBeClosed - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - ): HttpResponseFor = - executeAgent(sessionId, params, RequestOptions.none()) - - /** @see executeAgent */ - @MustBeClosed - fun executeAgent( - sessionId: String, - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - executeAgent(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see executeAgent */ - @MustBeClosed - fun executeAgent( - params: SessionExecuteAgentParams - ): HttpResponseFor = - executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - @MustBeClosed - fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/extract`, but is otherwise - * the same as [SessionService.extract]. - */ - @MustBeClosed - fun extract(sessionId: String): HttpResponseFor = - extract(sessionId, SessionExtractParams.none()) - - /** @see extract */ - @MustBeClosed - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - extract(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see extract */ - @MustBeClosed - fun extract( - sessionId: String, - params: SessionExtractParams = SessionExtractParams.none(), - ): HttpResponseFor = - extract(sessionId, params, RequestOptions.none()) - - /** @see extract */ - @MustBeClosed - fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor - - /** @see extract */ - @MustBeClosed - fun extract(params: SessionExtractParams): HttpResponseFor = - extract(params, RequestOptions.none()) - - /** @see extract */ - @MustBeClosed - fun extract( - sessionId: String, - requestOptions: RequestOptions, - ): HttpResponseFor = - extract(sessionId, SessionExtractParams.none(), requestOptions) - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/navigate`, but is otherwise - * the same as [SessionService.navigate]. - */ - @MustBeClosed - fun navigate( - sessionId: String, - params: SessionNavigateParams, - ): HttpResponseFor> = - navigate(sessionId, params, RequestOptions.none()) - - /** @see navigate */ - @MustBeClosed - fun navigate( - sessionId: String, - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor> = - navigate(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see navigate */ - @MustBeClosed - fun navigate( - params: SessionNavigateParams - ): HttpResponseFor> = - navigate(params, RequestOptions.none()) - - /** @see navigate */ - @MustBeClosed - fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor> - - /** - * Returns a raw HTTP response for `post /sessions/{sessionId}/observe`, but is otherwise - * the same as [SessionService.observe]. - */ - @MustBeClosed - fun observe(sessionId: String): HttpResponseFor> = - observe(sessionId, SessionObserveParams.none()) - - /** @see observe */ - @MustBeClosed - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor> = - observe(params.toBuilder().sessionId(sessionId).build(), requestOptions) - - /** @see observe */ - @MustBeClosed - fun observe( - sessionId: String, - params: SessionObserveParams = SessionObserveParams.none(), - ): HttpResponseFor> = observe(sessionId, params, RequestOptions.none()) - - /** @see observe */ - @MustBeClosed - fun observe( - params: SessionObserveParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor> - - /** @see observe */ - @MustBeClosed - fun observe(params: SessionObserveParams): HttpResponseFor> = - observe(params, RequestOptions.none()) - - /** @see observe */ - @MustBeClosed - fun observe( - sessionId: String, - requestOptions: RequestOptions, - ): HttpResponseFor> = - observe(sessionId, SessionObserveParams.none(), requestOptions) - /** * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as * [SessionService.start]. */ @MustBeClosed - fun start(params: SessionStartParams): HttpResponseFor = - start(params, RequestOptions.none()) + fun start(): HttpResponseFor = start(SessionStartParams.none()) /** @see start */ @MustBeClosed fun start( - params: SessionStartParams, + params: SessionStartParams = SessionStartParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see start */ + @MustBeClosed + fun start( + params: SessionStartParams = SessionStartParams.none() + ): HttpResponseFor = start(params, RequestOptions.none()) + + /** @see start */ + @MustBeClosed + fun start(requestOptions: RequestOptions): HttpResponseFor = + start(SessionStartParams.none(), requestOptions) } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index 6c09595..2a983bb 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -4,7 +4,6 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions -import com.browserbase.api.core.checkRequired import com.browserbase.api.core.handlers.errorBodyHandler import com.browserbase.api.core.handlers.errorHandler import com.browserbase.api.core.handlers.jsonHandler @@ -16,23 +15,9 @@ import com.browserbase.api.core.http.HttpResponseFor import com.browserbase.api.core.http.json import com.browserbase.api.core.http.parseable import com.browserbase.api.core.prepare -import com.browserbase.api.models.sessions.Action -import com.browserbase.api.models.sessions.SessionActParams -import com.browserbase.api.models.sessions.SessionActResponse -import com.browserbase.api.models.sessions.SessionEndParams -import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse -import com.browserbase.api.models.sessions.SessionExtractParams -import com.browserbase.api.models.sessions.SessionExtractResponse -import com.browserbase.api.models.sessions.SessionNavigateParams -import com.browserbase.api.models.sessions.SessionNavigateResponse -import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse -import java.util.Optional import java.util.function.Consumer -import kotlin.jvm.optionals.getOrNull class SessionServiceImpl internal constructor(private val clientOptions: ClientOptions) : SessionService { @@ -46,42 +31,6 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO override fun withOptions(modifier: Consumer): SessionService = SessionServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) - override fun act(params: SessionActParams, requestOptions: RequestOptions): SessionActResponse = - // post /sessions/{sessionId}/act - withRawResponse().act(params, requestOptions).parse() - - override fun end(params: SessionEndParams, requestOptions: RequestOptions): SessionEndResponse = - // post /sessions/{sessionId}/end - withRawResponse().end(params, requestOptions).parse() - - override fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions, - ): SessionExecuteAgentResponse = - // post /sessions/{sessionId}/agentExecute - withRawResponse().executeAgent(params, requestOptions).parse() - - override fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions, - ): SessionExtractResponse = - // post /sessions/{sessionId}/extract - withRawResponse().extract(params, requestOptions).parse() - - override fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions, - ): Optional = - // post /sessions/{sessionId}/navigate - withRawResponse().navigate(params, requestOptions).parse() - - override fun observe( - params: SessionObserveParams, - requestOptions: RequestOptions, - ): List = - // post /sessions/{sessionId}/observe - withRawResponse().observe(params, requestOptions).parse() - override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -102,192 +51,6 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO clientOptions.toBuilder().apply(modifier::accept).build() ) - private val actHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun act( - params: SessionActParams, - requestOptions: RequestOptions, - ): HttpResponseFor { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "act") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { actHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - - private val endHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun end( - params: SessionEndParams, - requestOptions: RequestOptions, - ): HttpResponseFor { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "end") - .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { endHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - - private val executeAgentHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions, - ): HttpResponseFor { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "agentExecute") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { executeAgentHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - - private val extractHandler: Handler = - jsonHandler(clientOptions.jsonMapper) - - override fun extract( - params: SessionExtractParams, - requestOptions: RequestOptions, - ): HttpResponseFor { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "extract") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { extractHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.validate() - } - } - } - } - - private val navigateHandler: Handler> = - jsonHandler>(clientOptions.jsonMapper) - - override fun navigate( - params: SessionNavigateParams, - requestOptions: RequestOptions, - ): HttpResponseFor> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "navigate") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { navigateHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.ifPresent { it.validate() } - } - } - } - } - - private val observeHandler: Handler> = - jsonHandler>(clientOptions.jsonMapper) - - override fun observe( - params: SessionObserveParams, - requestOptions: RequestOptions, - ): HttpResponseFor> { - // We check here instead of in the params builder because this can be specified - // positionally or in the params class. - checkRequired("sessionId", params.sessionId().getOrNull()) - val request = - HttpRequest.builder() - .method(HttpMethod.POST) - .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "observe") - .body(json(clientOptions.jsonMapper, params._body())) - .build() - .prepare(clientOptions, params) - val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) - val response = clientOptions.httpClient.execute(request, requestOptions) - return errorHandler.handle(response).parseable { - response - .use { observeHandler.handle(it) } - .also { - if (requestOptions.responseValidation!!) { - it.forEach { it.validate() } - } - } - } - } - private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt index fcd120c..4464f91 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt @@ -4,6 +4,7 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -13,18 +14,16 @@ internal class ActionTest { fun create() { val action = Action.builder() - .addArgument("string") - .description("description") - .method("method") - .selector("selector") - .backendNodeId(0L) + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") .build() - assertThat(action.arguments()).containsExactly("string") - assertThat(action.description()).isEqualTo("description") - assertThat(action.method()).isEqualTo("method") - assertThat(action.selector()).isEqualTo("selector") - assertThat(action.backendNodeId()).contains(0L) + assertThat(action.description()).isEqualTo("Click the submit button") + assertThat(action.selector()).isEqualTo("[data-testid='submit-button']") + assertThat(action.arguments().getOrNull()).containsExactly("Hello World") + assertThat(action.method()).contains("click") } @Test @@ -32,11 +31,10 @@ internal class ActionTest { val jsonMapper = jsonMapper() val action = Action.builder() - .addArgument("string") - .description("description") - .method("method") - .selector("selector") - .backendNodeId(0L) + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") .build() val roundtrippedAction = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index 0430aec..b45bc3f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -2,39 +2,66 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper +import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows internal class ModelConfigTest { @Test - fun create() { - val modelConfig = - ModelConfig.builder() + fun ofString() { + val string = "string" + + val modelConfig = ModelConfig.ofString(string) + + assertThat(modelConfig.string()).contains(string) + assertThat(modelConfig.unionMember1()).isEmpty + } + + @Test + fun ofStringRoundtrip() { + val jsonMapper = jsonMapper() + val modelConfig = ModelConfig.ofString("string") + + val roundtrippedModelConfig = + jsonMapper.readValue( + jsonMapper.writeValueAsString(modelConfig), + jacksonTypeRef(), + ) + + assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) + } + + @Test + fun ofUnionMember1() { + val unionMember1 = + ModelConfig.UnionMember1.builder() + .modelName("modelName") .apiKey("apiKey") .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) .build() - assertThat(modelConfig.apiKey()).contains("apiKey") - assertThat(modelConfig.baseUrl()).contains("https://example.com") - assertThat(modelConfig.model()).contains("model") - assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI) + val modelConfig = ModelConfig.ofUnionMember1(unionMember1) + + assertThat(modelConfig.string()).isEmpty + assertThat(modelConfig.unionMember1()).contains(unionMember1) } @Test - fun roundtrip() { + fun ofUnionMember1Roundtrip() { val jsonMapper = jsonMapper() val modelConfig = - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() + ModelConfig.ofUnionMember1( + ModelConfig.UnionMember1.builder() + .modelName("modelName") + .apiKey("apiKey") + .baseUrl("https://example.com") + .build() + ) val roundtrippedModelConfig = jsonMapper.readValue( @@ -44,4 +71,13 @@ internal class ModelConfigTest { assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) } + + @Test + fun incompatibleJsonShapeDeserializesToUnknown() { + val value = JsonValue.from(listOf("invalid", "array")) + val modelConfig = jsonMapper().convertValue(value, jacksonTypeRef()) + + val e = assertThrows { modelConfig.validate() } + assertThat(e).hasMessageStartingWith("Unknown ") + } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt deleted file mode 100644 index fbcca00..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ /dev/null @@ -1,166 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.http.Headers -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionActParamsTest { - - @Test - fun create() { - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("click the sign in button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - .build() - } - - @Test - fun pathParams() { - val params = - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .input("click the sign in button") - .build() - - assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun headers() { - val params = - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("click the sign in button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) - } - - @Test - fun headersWithoutOptionalFields() { - val params = - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .input("click the sign in button") - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun body() { - val params = - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("click the sign in button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - .build() - - val body = params._body() - - assertThat(body.input()) - .isEqualTo(SessionActParams.Input.ofString("click the sign in button")) - assertThat(body.frameId()).contains("frameId") - assertThat(body.options()) - .contains( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .input("click the sign in button") - .build() - - val body = params._body() - - assertThat(body.input()) - .isEqualTo(SessionActParams.Input.ofString("click the sign in button")) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt deleted file mode 100644 index 7f4d8c8..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionActResponseTest { - - @Test - fun create() { - val sessionActResponse = - SessionActResponse.builder() - .addAction( - Action.builder() - .addArgument("string") - .description("description") - .method("method") - .selector("selector") - .backendNodeId(0L) - .build() - ) - .message("message") - .success(true) - .build() - - assertThat(sessionActResponse.actions()) - .containsExactly( - Action.builder() - .addArgument("string") - .description("description") - .method("method") - .selector("selector") - .backendNodeId(0L) - .build() - ) - assertThat(sessionActResponse.message()).isEqualTo("message") - assertThat(sessionActResponse.success()).isEqualTo(true) - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val sessionActResponse = - SessionActResponse.builder() - .addAction( - Action.builder() - .addArgument("string") - .description("description") - .method("method") - .selector("selector") - .backendNodeId(0L) - .build() - ) - .message("message") - .success(true) - .build() - - val roundtrippedSessionActResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionActResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionActResponse).isEqualTo(sessionActResponse) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt deleted file mode 100644 index ab839e5..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionEndParamsTest { - - @Test - fun create() { - SessionEndParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - } - - @Test - fun pathParams() { - val params = - SessionEndParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt deleted file mode 100644 index b52414c..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt +++ /dev/null @@ -1,32 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionEndResponseTest { - - @Test - fun create() { - val sessionEndResponse = SessionEndResponse.builder().success(true).build() - - assertThat(sessionEndResponse.success()).contains(true) - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val sessionEndResponse = SessionEndResponse.builder().success(true).build() - - val roundtrippedSessionEndResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionEndResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionEndResponse).isEqualTo(sessionEndResponse) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt deleted file mode 100644 index 6d0d59b..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt +++ /dev/null @@ -1,170 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.http.Headers -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionExecuteAgentParamsTest { - - @Test - fun create() { - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) - .agentConfig( - SessionExecuteAgentParams.AgentConfig.builder() - .cua(true) - .model("openai/gpt-4o") - .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) - .systemPrompt("systemPrompt") - .build() - ) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .highlightCursor(true) - .maxSteps(10L) - .build() - ) - .frameId("frameId") - .build() - } - - @Test - fun pathParams() { - val params = - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .agentConfig(SessionExecuteAgentParams.AgentConfig.builder().build()) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .build() - ) - .build() - - assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun headers() { - val params = - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) - .agentConfig( - SessionExecuteAgentParams.AgentConfig.builder() - .cua(true) - .model("openai/gpt-4o") - .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) - .systemPrompt("systemPrompt") - .build() - ) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .highlightCursor(true) - .maxSteps(10L) - .build() - ) - .frameId("frameId") - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) - } - - @Test - fun headersWithoutOptionalFields() { - val params = - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .agentConfig(SessionExecuteAgentParams.AgentConfig.builder().build()) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .build() - ) - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun body() { - val params = - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) - .agentConfig( - SessionExecuteAgentParams.AgentConfig.builder() - .cua(true) - .model("openai/gpt-4o") - .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) - .systemPrompt("systemPrompt") - .build() - ) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .highlightCursor(true) - .maxSteps(10L) - .build() - ) - .frameId("frameId") - .build() - - val body = params._body() - - assertThat(body.agentConfig()) - .isEqualTo( - SessionExecuteAgentParams.AgentConfig.builder() - .cua(true) - .model("openai/gpt-4o") - .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) - .systemPrompt("systemPrompt") - .build() - ) - assertThat(body.executeOptions()) - .isEqualTo( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .highlightCursor(true) - .maxSteps(10L) - .build() - ) - assertThat(body.frameId()).contains("frameId") - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .agentConfig(SessionExecuteAgentParams.AgentConfig.builder().build()) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .build() - ) - .build() - - val body = params._body() - - assertThat(body.agentConfig()) - .isEqualTo(SessionExecuteAgentParams.AgentConfig.builder().build()) - assertThat(body.executeOptions()) - .isEqualTo( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .build() - ) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt deleted file mode 100644 index 4737af6..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionExecuteAgentResponseTest { - - @Test - fun create() { - val sessionExecuteAgentResponse = - SessionExecuteAgentResponse.builder().message("message").build() - - assertThat(sessionExecuteAgentResponse.message()).contains("message") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val sessionExecuteAgentResponse = - SessionExecuteAgentResponse.builder().message("message").build() - - val roundtrippedSessionExecuteAgentResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionExecuteAgentResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionExecuteAgentResponse).isEqualTo(sessionExecuteAgentResponse) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt deleted file mode 100644 index 7df72a7..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ /dev/null @@ -1,158 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.http.Headers -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionExtractParamsTest { - - @Test - fun create() { - SessionExtractParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("extract the page title") - .options( - SessionExtractParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .schema( - SessionExtractParams.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .build() - } - - @Test - fun pathParams() { - val params = - SessionExtractParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun headers() { - val params = - SessionExtractParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("extract the page title") - .options( - SessionExtractParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .schema( - SessionExtractParams.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) - } - - @Test - fun headersWithoutOptionalFields() { - val params = - SessionExtractParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun body() { - val params = - SessionExtractParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("extract the page title") - .options( - SessionExtractParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .schema( - SessionExtractParams.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .build() - - val body = params._body() - - assertThat(body.frameId()).contains("frameId") - assertThat(body.instruction()).contains("extract the page title") - assertThat(body.options()) - .contains( - SessionExtractParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - assertThat(body.schema()) - .contains( - SessionExtractParams.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - SessionExtractParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - val body = params._body() - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt deleted file mode 100644 index 42022d5..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt +++ /dev/null @@ -1,94 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.jsonMapper -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.EnumSource - -internal class SessionExtractResponseTest { - - @Test - fun ofExtraction() { - val extraction = - SessionExtractResponse.Extraction.builder().extraction("extraction").build() - - val sessionExtractResponse = SessionExtractResponse.ofExtraction(extraction) - - assertThat(sessionExtractResponse.extraction()).contains(extraction) - assertThat(sessionExtractResponse.custom()).isEmpty - } - - @Test - fun ofExtractionRoundtrip() { - val jsonMapper = jsonMapper() - val sessionExtractResponse = - SessionExtractResponse.ofExtraction( - SessionExtractResponse.Extraction.builder().extraction("extraction").build() - ) - - val roundtrippedSessionExtractResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionExtractResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) - } - - @Test - fun ofCustom() { - val custom = - SessionExtractResponse.Custom.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - - val sessionExtractResponse = SessionExtractResponse.ofCustom(custom) - - assertThat(sessionExtractResponse.extraction()).isEmpty - assertThat(sessionExtractResponse.custom()).contains(custom) - } - - @Test - fun ofCustomRoundtrip() { - val jsonMapper = jsonMapper() - val sessionExtractResponse = - SessionExtractResponse.ofCustom( - SessionExtractResponse.Custom.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - - val roundtrippedSessionExtractResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionExtractResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) - } - - enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { - BOOLEAN(JsonValue.from(false)), - STRING(JsonValue.from("invalid")), - INTEGER(JsonValue.from(-1)), - FLOAT(JsonValue.from(3.14)), - ARRAY(JsonValue.from(listOf("invalid", "array"))), - } - - @ParameterizedTest - @EnumSource - fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { - val sessionExtractResponse = - jsonMapper().convertValue(testCase.value, jacksonTypeRef()) - - val e = assertThrows { sessionExtractResponse.validate() } - assertThat(e).hasMessageStartingWith("Unknown ") - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt deleted file mode 100644 index fe762db..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt +++ /dev/null @@ -1,111 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.http.Headers -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionNavigateParamsTest { - - @Test - fun create() { - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) - .url("https://example.com") - .frameId("frameId") - .options( - SessionNavigateParams.Options.builder() - .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) - .build() - ) - .build() - } - - @Test - fun pathParams() { - val params = - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .url("https://example.com") - .build() - - assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun headers() { - val params = - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) - .url("https://example.com") - .frameId("frameId") - .options( - SessionNavigateParams.Options.builder() - .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) - .build() - ) - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) - } - - @Test - fun headersWithoutOptionalFields() { - val params = - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .url("https://example.com") - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun body() { - val params = - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) - .url("https://example.com") - .frameId("frameId") - .options( - SessionNavigateParams.Options.builder() - .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) - .build() - ) - .build() - - val body = params._body() - - assertThat(body.url()).isEqualTo("https://example.com") - assertThat(body.frameId()).contains("frameId") - assertThat(body.options()) - .contains( - SessionNavigateParams.Options.builder() - .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) - .build() - ) - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .url("https://example.com") - .build() - - val body = params._body() - - assertThat(body.url()).isEqualTo("https://example.com") - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt deleted file mode 100644 index 1385964..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt +++ /dev/null @@ -1,36 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionNavigateResponseTest { - - @Test - fun create() { - val sessionNavigateResponse = - SessionNavigateResponse.builder().ok(true).status(0L).url("url").build() - - assertThat(sessionNavigateResponse.ok()).contains(true) - assertThat(sessionNavigateResponse.status()).contains(0L) - assertThat(sessionNavigateResponse.url()).contains("url") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val sessionNavigateResponse = - SessionNavigateResponse.builder().ok(true).status(0L).url("url").build() - - val roundtrippedSessionNavigateResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionNavigateResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionNavigateResponse).isEqualTo(sessionNavigateResponse) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt deleted file mode 100644 index a8ab677..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ /dev/null @@ -1,136 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.http.Headers -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionObserveParamsTest { - - @Test - fun create() { - SessionObserveParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("instruction") - .options( - SessionObserveParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .build() - } - - @Test - fun pathParams() { - val params = - SessionObserveParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - assertThat(params._pathParam(0)).isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun headers() { - val params = - SessionObserveParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("instruction") - .options( - SessionObserveParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) - } - - @Test - fun headersWithoutOptionalFields() { - val params = - SessionObserveParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun body() { - val params = - SessionObserveParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("instruction") - .options( - SessionObserveParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .build() - - val body = params._body() - - assertThat(body.frameId()).contains("frameId") - assertThat(body.instruction()).contains("instruction") - assertThat(body.options()) - .contains( - SessionObserveParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - SessionObserveParams.builder().sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e").build() - - val body = params._body() - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 9454bf3..627f9ae 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -2,6 +2,8 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -10,51 +12,59 @@ internal class SessionStartParamsTest { @Test fun create() { SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() } @Test - fun body() { + fun headers() { val params = SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() - val body = params._body() + val headers = params._headers() - assertThat(body.browserbaseApiKey()).isEqualTo("BROWSERBASE_API_KEY") - assertThat(body.browserbaseProjectId()).isEqualTo("BROWSERBASE_PROJECT_ID") - assertThat(body.domSettleTimeout()).contains(0L) - assertThat(body.model()).contains("openai/gpt-4o") - assertThat(body.selfHeal()).contains(true) - assertThat(body.systemPrompt()).contains("systemPrompt") - assertThat(body.verbose()).contains(1L) + assertThat(headers).isEqualTo(Headers.builder().build()) } @Test - fun bodyWithoutOptionalFields() { + fun headersWithoutOptionalFields() { + val params = SessionStartParams.builder().build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { val params = SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() val body = params._body() - assertThat(body.browserbaseApiKey()).isEqualTo("BROWSERBASE_API_KEY") - assertThat(body.browserbaseProjectId()).isEqualTo("BROWSERBASE_PROJECT_ID") + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = SessionStartParams.builder().build() + + val body = params._body() } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt index 714c73d..51616d7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt @@ -11,25 +11,13 @@ internal class SessionStartResponseTest { @Test fun create() { - val sessionStartResponse = - SessionStartResponse.builder() - .available(true) - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() - - assertThat(sessionStartResponse.available()).isEqualTo(true) - assertThat(sessionStartResponse.sessionId()) - .isEqualTo("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") + val sessionStartResponse = SessionStartResponse.builder().build() } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionStartResponse = - SessionStartResponse.builder() - .available(true) - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .build() + val sessionStartResponse = SessionStartResponse.builder().build() val roundtrippedSessionStartResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 509b889..ccf1223 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -74,13 +74,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -104,13 +102,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -134,13 +130,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -164,13 +158,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -194,13 +186,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -224,13 +214,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -254,13 +242,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -284,13 +270,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -314,13 +298,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -344,13 +326,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -374,13 +354,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -404,13 +382,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -434,13 +410,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -464,13 +438,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -494,13 +466,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -524,13 +494,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } @@ -552,13 +520,11 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index aa39440..8af7ae3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -5,12 +5,9 @@ package com.browserbase.api.services import com.browserbase.api.client.StagehandClient import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue -import com.browserbase.api.models.sessions.ModelConfig -import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.equalTo -import com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath import com.github.tomakehurst.wiremock.client.WireMock.ok import com.github.tomakehurst.wiremock.client.WireMock.post import com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor @@ -48,16 +45,13 @@ internal class ServiceParamsTest { sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") - .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) .build() ) @@ -65,51 +59,6 @@ internal class ServiceParamsTest { postRequestedFor(anyUrl()) .withHeader("Secret-Header", equalTo("42")) .withQueryParam("secret_query_param", equalTo("42")) - .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) - ) - } - - @Disabled("Prism tests are disabled") - @Test - fun act() { - val sessionService = client.sessions() - stubFor(post(anyUrl()).willReturn(ok("{}"))) - - sessionService.act( - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("click the sign in button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - .putAdditionalHeader("Secret-Header", "42") - .putAdditionalQueryParam("secret_query_param", "42") - .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) - .build() - ) - - verify( - postRequestedFor(anyUrl()) - .withHeader("Secret-Header", equalTo("42")) - .withQueryParam("secret_query_param", equalTo("42")) - .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) ) } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index d041842..57ff039 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -5,14 +5,7 @@ package com.browserbase.api.services.async import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync import com.browserbase.api.core.JsonValue -import com.browserbase.api.models.sessions.ModelConfig -import com.browserbase.api.models.sessions.SessionActParams -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExtractParams -import com.browserbase.api.models.sessions.SessionNavigateParams -import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams -import kotlin.jvm.optionals.getOrNull import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,225 +13,6 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) internal class SessionServiceAsyncTest { - @Disabled("Prism tests are disabled") - @Test - fun act() { - val client = - StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionServiceAsync = client.sessions() - - val responseFuture = - sessionServiceAsync.act( - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("click the sign in button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - .build() - ) - - val response = responseFuture.get() - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun end() { - val client = - StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionServiceAsync = client.sessions() - - val responseFuture = sessionServiceAsync.end("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - - val response = responseFuture.get() - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun executeAgent() { - val client = - StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionServiceAsync = client.sessions() - - val responseFuture = - sessionServiceAsync.executeAgent( - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) - .agentConfig( - SessionExecuteAgentParams.AgentConfig.builder() - .cua(true) - .model("openai/gpt-4o") - .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) - .systemPrompt("systemPrompt") - .build() - ) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .highlightCursor(true) - .maxSteps(10L) - .build() - ) - .frameId("frameId") - .build() - ) - - val response = responseFuture.get() - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun extract() { - val client = - StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionServiceAsync = client.sessions() - - val responseFuture = - sessionServiceAsync.extract( - SessionExtractParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("extract the page title") - .options( - SessionExtractParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .schema( - SessionExtractParams.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .build() - ) - - val response = responseFuture.get() - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun navigate() { - val client = - StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionServiceAsync = client.sessions() - - val responseFuture = - sessionServiceAsync.navigate( - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) - .url("https://example.com") - .frameId("frameId") - .options( - SessionNavigateParams.Options.builder() - .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) - .build() - ) - .build() - ) - - val response = responseFuture.get() - val unwrappedResponse = response.getOrNull() - unwrappedResponse?.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun observe() { - val client = - StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionServiceAsync = client.sessions() - - val actionsFuture = - sessionServiceAsync.observe( - SessionObserveParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("instruction") - .options( - SessionObserveParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .build() - ) - - val actions = actionsFuture.get() - actions.forEach { it.validate() } - } - @Disabled("Prism tests are disabled") @Test fun start() { @@ -254,13 +28,11 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 10177a3..c782cd2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -5,14 +5,7 @@ package com.browserbase.api.services.blocking import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue -import com.browserbase.api.models.sessions.ModelConfig -import com.browserbase.api.models.sessions.SessionActParams -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExtractParams -import com.browserbase.api.models.sessions.SessionNavigateParams -import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams -import kotlin.jvm.optionals.getOrNull import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,219 +13,6 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) internal class SessionServiceTest { - @Disabled("Prism tests are disabled") - @Test - fun act() { - val client = - StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionService = client.sessions() - - val response = - sessionService.act( - SessionActParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("click the sign in button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .timeout(0L) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) - .build() - ) - .build() - ) - .build() - ) - - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun end() { - val client = - StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionService = client.sessions() - - val response = sessionService.end("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun executeAgent() { - val client = - StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionService = client.sessions() - - val response = - sessionService.executeAgent( - SessionExecuteAgentParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExecuteAgentParams.XStreamResponse.TRUE) - .agentConfig( - SessionExecuteAgentParams.AgentConfig.builder() - .cua(true) - .model("openai/gpt-4o") - .provider(SessionExecuteAgentParams.AgentConfig.Provider.OPENAI) - .systemPrompt("systemPrompt") - .build() - ) - .executeOptions( - SessionExecuteAgentParams.ExecuteOptions.builder() - .instruction("Find and click the first product") - .highlightCursor(true) - .maxSteps(10L) - .build() - ) - .frameId("frameId") - .build() - ) - - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun extract() { - val client = - StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionService = client.sessions() - - val response = - sessionService.extract( - SessionExtractParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("extract the page title") - .options( - SessionExtractParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .schema( - SessionExtractParams.Schema.builder() - .putAdditionalProperty("foo", JsonValue.from("bar")) - .build() - ) - .build() - ) - - response.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun navigate() { - val client = - StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionService = client.sessions() - - val response = - sessionService.navigate( - SessionNavigateParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) - .url("https://example.com") - .frameId("frameId") - .options( - SessionNavigateParams.Options.builder() - .waitUntil(SessionNavigateParams.Options.WaitUntil.LOAD) - .build() - ) - .build() - ) - - val unwrappedResponse = response.getOrNull() - unwrappedResponse?.validate() - } - - @Disabled("Prism tests are disabled") - @Test - fun observe() { - val client = - StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) - .browserbaseApiKey("My Browserbase API Key") - .browserbaseProjectId("My Browserbase Project ID") - .modelApiKey("My Model API Key") - .build() - val sessionService = client.sessions() - - val actions = - sessionService.observe( - SessionObserveParams.builder() - .sessionId("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e") - .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) - .frameId("frameId") - .instruction("instruction") - .options( - SessionObserveParams.Options.builder() - .model( - ModelConfig.builder() - .apiKey("apiKey") - .baseUrl("https://example.com") - .model("model") - .provider(ModelConfig.Provider.OPENAI) - .build() - ) - .selector("selector") - .timeout(0L) - .build() - ) - .build() - ) - - actions.forEach { it.validate() } - } - @Disabled("Prism tests are disabled") @Test fun start() { @@ -248,13 +28,11 @@ internal class SessionServiceTest { val response = sessionService.start( SessionStartParams.builder() - .browserbaseApiKey("BROWSERBASE_API_KEY") - .browserbaseProjectId("BROWSERBASE_PROJECT_ID") - .domSettleTimeout(0L) - .model("openai/gpt-4o") - .selfHeal(true) - .systemPrompt("systemPrompt") - .verbose(1L) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) .build() ) diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 3960aa2..63da21d 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -5,7 +5,7 @@ package com.browserbase.api.proguard import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.jsonMapper import com.browserbase.api.models.sessions.Action -import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.ModelConfig import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import kotlin.reflect.full.memberFunctions import kotlin.reflect.jvm.javaMethod @@ -61,11 +61,10 @@ internal class ProGuardCompatibilityTest { val jsonMapper = jsonMapper() val action = Action.builder() - .addArgument("string") - .description("description") - .method("method") - .selector("selector") - .backendNodeId(0L) + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") .build() val roundtrippedAction = @@ -75,19 +74,16 @@ internal class ProGuardCompatibilityTest { } @Test - fun sessionExtractResponseRoundtrip() { + fun modelConfigRoundtrip() { val jsonMapper = jsonMapper() - val sessionExtractResponse = - SessionExtractResponse.ofExtraction( - SessionExtractResponse.Extraction.builder().extraction("extraction").build() - ) + val modelConfig = ModelConfig.ofString("string") - val roundtrippedSessionExtractResponse = + val roundtrippedModelConfig = jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionExtractResponse), - jacksonTypeRef(), + jsonMapper.writeValueAsString(modelConfig), + jacksonTypeRef(), ) - assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) + assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) } } From 12470947de1184199444b96efae74ee5125718ff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 02:15:15 +0000 Subject: [PATCH 027/164] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f5e93e0..855c5aa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 1 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-516862e7e90968bc55ac44ce7ffe2d5c1f738c11757471c2b9e0e4cff9384f2c.yml -openapi_spec_hash: 19bbe52a6ae0eec7fc3f6698e831ee55 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-24dc965121b5ad70c846fd8b96ce4638d13bac7e86ba0f50a8d13a5664ac4929.yml +openapi_spec_hash: 5a8e70d2a5358bfd6917f907b4a4d1f3 config_hash: a35b56eb05306a0f02e83c11d57f975f From 13593fb9691eec6d64533e6cdad2eccc94971270 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 02:40:24 +0000 Subject: [PATCH 028/164] feat(api): manual updates --- .stats.yml | 8 +- README.md | 14 + .../api/models/sessions/SessionActParams.kt | 267 ++++++++++ .../api/models/sessions/SessionActResponse.kt | 113 +++++ .../api/models/sessions/SessionEndParams.kt | 289 +++++++++++ .../api/models/sessions/SessionEndResponse.kt | 113 +++++ .../sessions/SessionExecuteAgentParams.kt | 269 ++++++++++ .../sessions/SessionExecuteAgentResponse.kt | 118 +++++ .../models/sessions/SessionExtractParams.kt | 267 ++++++++++ .../models/sessions/SessionExtractResponse.kt | 114 +++++ .../models/sessions/SessionNavigateParams.kt | 267 ++++++++++ .../sessions/SessionNavigateResponse.kt | 115 +++++ .../models/sessions/SessionObserveParams.kt | 269 ++++++++++ .../models/sessions/SessionObserveResponse.kt | 114 +++++ .../api/services/async/SessionServiceAsync.kt | 466 ++++++++++++++++++ .../services/async/SessionServiceAsyncImpl.kt | 240 +++++++++ .../api/services/blocking/SessionService.kt | 459 +++++++++++++++++ .../services/blocking/SessionServiceImpl.kt | 216 ++++++++ .../models/sessions/SessionActParamsTest.kt | 82 +++ .../models/sessions/SessionActResponseTest.kt | 30 ++ .../models/sessions/SessionEndParamsTest.kt | 56 +++ .../models/sessions/SessionEndResponseTest.kt | 30 ++ .../sessions/SessionExecuteAgentParamsTest.kt | 85 ++++ .../SessionExecuteAgentResponseTest.kt | 30 ++ .../sessions/SessionExtractParamsTest.kt | 82 +++ .../sessions/SessionExtractResponseTest.kt | 30 ++ .../sessions/SessionNavigateParamsTest.kt | 85 ++++ .../sessions/SessionNavigateResponseTest.kt | 30 ++ .../sessions/SessionObserveParamsTest.kt | 82 +++ .../sessions/SessionObserveResponseTest.kt | 30 ++ .../services/async/SessionServiceAsyncTest.kt | 173 +++++++ .../services/blocking/SessionServiceTest.kt | 167 +++++++ 32 files changed, 4706 insertions(+), 4 deletions(-) create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt diff --git a/.stats.yml b/.stats.yml index 855c5aa..c436ede 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 1 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-24dc965121b5ad70c846fd8b96ce4638d13bac7e86ba0f50a8d13a5664ac4929.yml -openapi_spec_hash: 5a8e70d2a5358bfd6917f907b4a4d1f3 -config_hash: a35b56eb05306a0f02e83c11d57f975f +configured_endpoints: 7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-c1a6f03afe5d6823c198e5ac476fb688dacc783dae1fefdf6bf142084e298e16.yml +openapi_spec_hash: d20e8f697ce8d5bb80295fc1e8ce02e8 +config_hash: e457d704d820df5d25acfd379169f132 diff --git a/README.md b/README.md index ae4e26a..1bab387 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,20 @@ JsonValue complexValue = JsonValue.from(Map.of( )); ``` +Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. + +To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt): + +```java +import com.browserbase.api.core.JsonMissing; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionStartParams; + +SessionStartParams params = SessionActParams.builder() + .id(JsonMissing.of()) + .build(); +``` + ### Response properties To access undocumented response properties, call the `_additionalProperties()` method: diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt new file mode 100644 index 0000000..9992e1f --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -0,0 +1,267 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Executes a browser action using natural language instructions or a predefined Action object. */ +class SessionActParams +private constructor( + private val id: JsonValue?, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val body: JsonValue, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + fun body(): JsonValue = body + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionActParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionActParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionActParams]. */ + class Builder internal constructor() { + + private var id: JsonValue? = null + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var body: JsonValue = JsonMissing.of() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionActParams: SessionActParams) = apply { + id = sessionActParams.id + xLanguage = sessionActParams.xLanguage + xSdkVersion = sessionActParams.xSdkVersion + xSentAt = sessionActParams.xSentAt + xStreamResponse = sessionActParams.xStreamResponse + body = sessionActParams.body + additionalHeaders = sessionActParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionActParams.additionalQueryParams.toBuilder() + } + + fun id(id: JsonValue?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun body(body: JsonValue) = apply { this.body = body } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionActParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionActParams = + SessionActParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): JsonValue = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id?.toString() ?: "" + else -> "" + } + + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionActParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SessionActParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt new file mode 100644 index 0000000..57b8827 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -0,0 +1,113 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections +import java.util.Objects + +class SessionActResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { + + @JsonCreator private constructor() : this(mutableMapOf()) + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionActResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionActResponse]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionActResponse: SessionActResponse) = apply { + additionalProperties = sessionActResponse.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionActResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionActResponse = SessionActResponse(additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionActResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionActResponse && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "SessionActResponse{additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt new file mode 100644 index 0000000..02f9cb0 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -0,0 +1,289 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Terminates the browser session and releases all associated resources. */ +class SessionEndParams +private constructor( + private val id: JsonValue?, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionEndParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionEndParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionEndParams]. */ + class Builder internal constructor() { + + private var id: JsonValue? = null + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionEndParams: SessionEndParams) = apply { + id = sessionEndParams.id + xLanguage = sessionEndParams.xLanguage + xSdkVersion = sessionEndParams.xSdkVersion + xSentAt = sessionEndParams.xSentAt + xStreamResponse = sessionEndParams.xStreamResponse + additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionEndParams.additionalQueryParams.toBuilder() + additionalBodyProperties = sessionEndParams.additionalBodyProperties.toMutableMap() + } + + fun id(id: JsonValue?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [SessionEndParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionEndParams = + SessionEndParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id?.toString() ?: "" + else -> "" + } + + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionEndParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) + + override fun toString() = + "SessionEndParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt new file mode 100644 index 0000000..970e0fd --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -0,0 +1,113 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections +import java.util.Objects + +class SessionEndResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { + + @JsonCreator private constructor() : this(mutableMapOf()) + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionEndResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionEndResponse]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionEndResponse: SessionEndResponse) = apply { + additionalProperties = sessionEndResponse.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionEndResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionEndResponse = SessionEndResponse(additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionEndResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionEndResponse && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "SessionEndResponse{additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt new file mode 100644 index 0000000..eca9552 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt @@ -0,0 +1,269 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ +class SessionExecuteAgentParams +private constructor( + private val id: JsonValue?, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val body: JsonValue, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + fun body(): JsonValue = body + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionExecuteAgentParams = builder().build() + + /** + * Returns a mutable builder for constructing an instance of [SessionExecuteAgentParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExecuteAgentParams]. */ + class Builder internal constructor() { + + private var id: JsonValue? = null + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var body: JsonValue = JsonMissing.of() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionExecuteAgentParams: SessionExecuteAgentParams) = apply { + id = sessionExecuteAgentParams.id + xLanguage = sessionExecuteAgentParams.xLanguage + xSdkVersion = sessionExecuteAgentParams.xSdkVersion + xSentAt = sessionExecuteAgentParams.xSentAt + xStreamResponse = sessionExecuteAgentParams.xStreamResponse + body = sessionExecuteAgentParams.body + additionalHeaders = sessionExecuteAgentParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionExecuteAgentParams.additionalQueryParams.toBuilder() + } + + fun id(id: JsonValue?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun body(body: JsonValue) = apply { this.body = body } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionExecuteAgentParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionExecuteAgentParams = + SessionExecuteAgentParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): JsonValue = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id?.toString() ?: "" + else -> "" + } + + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExecuteAgentParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SessionExecuteAgentParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt new file mode 100644 index 0000000..700a7ba --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt @@ -0,0 +1,118 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections +import java.util.Objects + +class SessionExecuteAgentResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { + + @JsonCreator private constructor() : this(mutableMapOf()) + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionExecuteAgentResponse]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExecuteAgentResponse]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionExecuteAgentResponse: SessionExecuteAgentResponse) = apply { + additionalProperties = sessionExecuteAgentResponse.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionExecuteAgentResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionExecuteAgentResponse = + SessionExecuteAgentResponse(additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionExecuteAgentResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExecuteAgentResponse && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionExecuteAgentResponse{additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt new file mode 100644 index 0000000..18414ff --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -0,0 +1,267 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Extracts structured data from the current page using AI-powered analysis. */ +class SessionExtractParams +private constructor( + private val id: JsonValue?, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val body: JsonValue, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + fun body(): JsonValue = body + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionExtractParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionExtractParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExtractParams]. */ + class Builder internal constructor() { + + private var id: JsonValue? = null + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var body: JsonValue = JsonMissing.of() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionExtractParams: SessionExtractParams) = apply { + id = sessionExtractParams.id + xLanguage = sessionExtractParams.xLanguage + xSdkVersion = sessionExtractParams.xSdkVersion + xSentAt = sessionExtractParams.xSentAt + xStreamResponse = sessionExtractParams.xStreamResponse + body = sessionExtractParams.body + additionalHeaders = sessionExtractParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionExtractParams.additionalQueryParams.toBuilder() + } + + fun id(id: JsonValue?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun body(body: JsonValue) = apply { this.body = body } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionExtractParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionExtractParams = + SessionExtractParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): JsonValue = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id?.toString() ?: "" + else -> "" + } + + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExtractParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SessionExtractParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt new file mode 100644 index 0000000..1e08b0f --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -0,0 +1,114 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections +import java.util.Objects + +class SessionExtractResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { + + @JsonCreator private constructor() : this(mutableMapOf()) + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionExtractResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExtractResponse]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionExtractResponse: SessionExtractResponse) = apply { + additionalProperties = sessionExtractResponse.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionExtractResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionExtractResponse = + SessionExtractResponse(additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionExtractResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExtractResponse && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "SessionExtractResponse{additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt new file mode 100644 index 0000000..9f282ab --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -0,0 +1,267 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Navigates the browser to the specified URL. */ +class SessionNavigateParams +private constructor( + private val id: JsonValue?, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val body: JsonValue, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + fun body(): JsonValue = body + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionNavigateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionNavigateParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionNavigateParams]. */ + class Builder internal constructor() { + + private var id: JsonValue? = null + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var body: JsonValue = JsonMissing.of() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionNavigateParams: SessionNavigateParams) = apply { + id = sessionNavigateParams.id + xLanguage = sessionNavigateParams.xLanguage + xSdkVersion = sessionNavigateParams.xSdkVersion + xSentAt = sessionNavigateParams.xSentAt + xStreamResponse = sessionNavigateParams.xStreamResponse + body = sessionNavigateParams.body + additionalHeaders = sessionNavigateParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionNavigateParams.additionalQueryParams.toBuilder() + } + + fun id(id: JsonValue?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun body(body: JsonValue) = apply { this.body = body } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionNavigateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionNavigateParams = + SessionNavigateParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): JsonValue = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id?.toString() ?: "" + else -> "" + } + + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionNavigateParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SessionNavigateParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt new file mode 100644 index 0000000..916d1a2 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -0,0 +1,115 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections +import java.util.Objects + +class SessionNavigateResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { + + @JsonCreator private constructor() : this(mutableMapOf()) + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionNavigateResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionNavigateResponse]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionNavigateResponse: SessionNavigateResponse) = apply { + additionalProperties = sessionNavigateResponse.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionNavigateResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionNavigateResponse = + SessionNavigateResponse(additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionNavigateResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionNavigateResponse && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "SessionNavigateResponse{additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt new file mode 100644 index 0000000..3f4fb2b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -0,0 +1,269 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Identifies and returns available actions on the current page that match the given instruction. + */ +class SessionObserveParams +private constructor( + private val id: JsonValue?, + private val xLanguage: JsonValue?, + private val xSdkVersion: JsonValue?, + private val xSentAt: JsonValue?, + private val xStreamResponse: JsonValue?, + private val body: JsonValue, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + fun id(): Optional = Optional.ofNullable(id) + + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + fun body(): JsonValue = body + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionObserveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionObserveParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionObserveParams]. */ + class Builder internal constructor() { + + private var id: JsonValue? = null + private var xLanguage: JsonValue? = null + private var xSdkVersion: JsonValue? = null + private var xSentAt: JsonValue? = null + private var xStreamResponse: JsonValue? = null + private var body: JsonValue = JsonMissing.of() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionObserveParams: SessionObserveParams) = apply { + id = sessionObserveParams.id + xLanguage = sessionObserveParams.xLanguage + xSdkVersion = sessionObserveParams.xSdkVersion + xSentAt = sessionObserveParams.xSentAt + xStreamResponse = sessionObserveParams.xStreamResponse + body = sessionObserveParams.body + additionalHeaders = sessionObserveParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionObserveParams.additionalQueryParams.toBuilder() + } + + fun id(id: JsonValue?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun body(body: JsonValue) = apply { this.body = body } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionObserveParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionObserveParams = + SessionObserveParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): JsonValue = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id?.toString() ?: "" + else -> "" + } + + override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionObserveParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SessionObserveParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt new file mode 100644 index 0000000..a27fc10 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt @@ -0,0 +1,114 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Collections +import java.util.Objects + +class SessionObserveResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor(private val additionalProperties: MutableMap) { + + @JsonCreator private constructor() : this(mutableMapOf()) + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SessionObserveResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionObserveResponse]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionObserveResponse: SessionObserveResponse) = apply { + additionalProperties = sessionObserveResponse.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionObserveResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionObserveResponse = + SessionObserveResponse(additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SessionObserveResponse = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionObserveResponse && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "SessionObserveResponse{additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index d481fec..435bf27 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -3,8 +3,21 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import java.util.concurrent.CompletableFuture @@ -24,6 +37,215 @@ interface SessionServiceAsync { */ fun withOptions(modifier: Consumer): SessionServiceAsync + /** + * Executes a browser action using natural language instructions or a predefined Action object. + */ + fun act(id: JsonValue): CompletableFuture = act(id, SessionActParams.none()) + + /** @see act */ + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + act(params.toBuilder().id(id).build(), requestOptions) + + /** @see act */ + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + ): CompletableFuture = act(id, params, RequestOptions.none()) + + /** @see act */ + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see act */ + fun act(params: SessionActParams): CompletableFuture = + act(params, RequestOptions.none()) + + /** @see act */ + fun act(id: JsonValue, requestOptions: RequestOptions): CompletableFuture = + act(id, SessionActParams.none(), requestOptions) + + /** Terminates the browser session and releases all associated resources. */ + fun end(id: JsonValue): CompletableFuture = end(id, SessionEndParams.none()) + + /** @see end */ + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + end(params.toBuilder().id(id).build(), requestOptions) + + /** @see end */ + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + ): CompletableFuture = end(id, params, RequestOptions.none()) + + /** @see end */ + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see end */ + fun end(params: SessionEndParams): CompletableFuture = + end(params, RequestOptions.none()) + + /** @see end */ + fun end(id: JsonValue, requestOptions: RequestOptions): CompletableFuture = + end(id, SessionEndParams.none(), requestOptions) + + /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ + fun executeAgent(id: JsonValue): CompletableFuture = + executeAgent(id, SessionExecuteAgentParams.none()) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + executeAgent(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + ): CompletableFuture = + executeAgent(id, params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams + ): CompletableFuture = executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture = + executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + + /** Extracts structured data from the current page using AI-powered analysis. */ + fun extract(id: JsonValue): CompletableFuture = + extract(id, SessionExtractParams.none()) + + /** @see extract */ + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + extract(params.toBuilder().id(id).build(), requestOptions) + + /** @see extract */ + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + ): CompletableFuture = extract(id, params, RequestOptions.none()) + + /** @see extract */ + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see extract */ + fun extract(params: SessionExtractParams): CompletableFuture = + extract(params, RequestOptions.none()) + + /** @see extract */ + fun extract( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture = + extract(id, SessionExtractParams.none(), requestOptions) + + /** Navigates the browser to the specified URL. */ + fun navigate(id: JsonValue): CompletableFuture = + navigate(id, SessionNavigateParams.none()) + + /** @see navigate */ + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + navigate(params.toBuilder().id(id).build(), requestOptions) + + /** @see navigate */ + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + ): CompletableFuture = navigate(id, params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see navigate */ + fun navigate(params: SessionNavigateParams): CompletableFuture = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture = + navigate(id, SessionNavigateParams.none(), requestOptions) + + /** + * Identifies and returns available actions on the current page that match the given + * instruction. + */ + fun observe(id: JsonValue): CompletableFuture = + observe(id, SessionObserveParams.none()) + + /** @see observe */ + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + observe(params.toBuilder().id(id).build(), requestOptions) + + /** @see observe */ + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + ): CompletableFuture = observe(id, params, RequestOptions.none()) + + /** @see observe */ + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see observe */ + fun observe(params: SessionObserveParams): CompletableFuture = + observe(params, RequestOptions.none()) + + /** @see observe */ + fun observe( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture = + observe(id, SessionObserveParams.none(), requestOptions) + /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. @@ -59,6 +281,250 @@ interface SessionServiceAsync { modifier: Consumer ): SessionServiceAsync.WithRawResponse + /** + * Returns a raw HTTP response for `post /sessions/{id}/act`, but is otherwise the same as + * [SessionServiceAsync.act]. + */ + fun act(id: JsonValue): CompletableFuture> = + act(id, SessionActParams.none()) + + /** @see act */ + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + act(params.toBuilder().id(id).build(), requestOptions) + + /** @see act */ + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + ): CompletableFuture> = + act(id, params, RequestOptions.none()) + + /** @see act */ + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see act */ + fun act(params: SessionActParams): CompletableFuture> = + act(params, RequestOptions.none()) + + /** @see act */ + fun act( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture> = + act(id, SessionActParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/end`, but is otherwise the same as + * [SessionServiceAsync.end]. + */ + fun end(id: JsonValue): CompletableFuture> = + end(id, SessionEndParams.none()) + + /** @see end */ + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + end(params.toBuilder().id(id).build(), requestOptions) + + /** @see end */ + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + ): CompletableFuture> = + end(id, params, RequestOptions.none()) + + /** @see end */ + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see end */ + fun end(params: SessionEndParams): CompletableFuture> = + end(params, RequestOptions.none()) + + /** @see end */ + fun end( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture> = + end(id, SessionEndParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/agentExecute`, but is otherwise the + * same as [SessionServiceAsync.executeAgent]. + */ + fun executeAgent( + id: JsonValue + ): CompletableFuture> = + executeAgent(id, SessionExecuteAgentParams.none()) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + executeAgent(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + ): CompletableFuture> = + executeAgent(id, params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams + ): CompletableFuture> = + executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture> = + executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/extract`, but is otherwise the same + * as [SessionServiceAsync.extract]. + */ + fun extract(id: JsonValue): CompletableFuture> = + extract(id, SessionExtractParams.none()) + + /** @see extract */ + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + extract(params.toBuilder().id(id).build(), requestOptions) + + /** @see extract */ + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + ): CompletableFuture> = + extract(id, params, RequestOptions.none()) + + /** @see extract */ + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see extract */ + fun extract( + params: SessionExtractParams + ): CompletableFuture> = + extract(params, RequestOptions.none()) + + /** @see extract */ + fun extract( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture> = + extract(id, SessionExtractParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/navigate`, but is otherwise the same + * as [SessionServiceAsync.navigate]. + */ + fun navigate(id: JsonValue): CompletableFuture> = + navigate(id, SessionNavigateParams.none()) + + /** @see navigate */ + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + navigate(params.toBuilder().id(id).build(), requestOptions) + + /** @see navigate */ + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + ): CompletableFuture> = + navigate(id, params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams + ): CompletableFuture> = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture> = + navigate(id, SessionNavigateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/observe`, but is otherwise the same + * as [SessionServiceAsync.observe]. + */ + fun observe(id: JsonValue): CompletableFuture> = + observe(id, SessionObserveParams.none()) + + /** @see observe */ + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + observe(params.toBuilder().id(id).build(), requestOptions) + + /** @see observe */ + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + ): CompletableFuture> = + observe(id, params, RequestOptions.none()) + + /** @see observe */ + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see observe */ + fun observe( + params: SessionObserveParams + ): CompletableFuture> = + observe(params, RequestOptions.none()) + + /** @see observe */ + fun observe( + id: JsonValue, + requestOptions: RequestOptions, + ): CompletableFuture> = + observe(id, SessionObserveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as * [SessionServiceAsync.start]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 056c59c..7746896 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -15,6 +15,18 @@ import com.browserbase.api.core.http.HttpResponseFor import com.browserbase.api.core.http.json import com.browserbase.api.core.http.parseable import com.browserbase.api.core.prepareAsync +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import java.util.concurrent.CompletableFuture @@ -32,6 +44,48 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl override fun withOptions(modifier: Consumer): SessionServiceAsync = SessionServiceAsyncImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + override fun act( + params: SessionActParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{id}/act + withRawResponse().act(params, requestOptions).thenApply { it.parse() } + + override fun end( + params: SessionEndParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{id}/end + withRawResponse().end(params, requestOptions).thenApply { it.parse() } + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{id}/agentExecute + withRawResponse().executeAgent(params, requestOptions).thenApply { it.parse() } + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{id}/extract + withRawResponse().extract(params, requestOptions).thenApply { it.parse() } + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{id}/navigate + withRawResponse().navigate(params, requestOptions).thenApply { it.parse() } + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /sessions/{id}/observe + withRawResponse().observe(params, requestOptions).thenApply { it.parse() } + override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -52,6 +106,192 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl clientOptions.toBuilder().apply(modifier::accept).build() ) + private val actHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun act( + params: SessionActParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "act") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { actHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val endHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun end( + params: SessionEndParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "end") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { endHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val executeAgentHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "agentExecute") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { executeAgentHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val extractHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "extract") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { extractHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val navigateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "navigate") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { navigateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val observeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "observe") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { observeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index ddd7ad3..f29cc14 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -3,8 +3,21 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import com.google.errorprone.annotations.MustBeClosed @@ -24,6 +37,187 @@ interface SessionService { */ fun withOptions(modifier: Consumer): SessionService + /** + * Executes a browser action using natural language instructions or a predefined Action object. + */ + fun act(id: JsonValue): SessionActResponse = act(id, SessionActParams.none()) + + /** @see act */ + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionActResponse = act(params.toBuilder().id(id).build(), requestOptions) + + /** @see act */ + fun act(id: JsonValue, params: SessionActParams = SessionActParams.none()): SessionActResponse = + act(id, params, RequestOptions.none()) + + /** @see act */ + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionActResponse + + /** @see act */ + fun act(params: SessionActParams): SessionActResponse = act(params, RequestOptions.none()) + + /** @see act */ + fun act(id: JsonValue, requestOptions: RequestOptions): SessionActResponse = + act(id, SessionActParams.none(), requestOptions) + + /** Terminates the browser session and releases all associated resources. */ + fun end(id: JsonValue): SessionEndResponse = end(id, SessionEndParams.none()) + + /** @see end */ + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionEndResponse = end(params.toBuilder().id(id).build(), requestOptions) + + /** @see end */ + fun end(id: JsonValue, params: SessionEndParams = SessionEndParams.none()): SessionEndResponse = + end(id, params, RequestOptions.none()) + + /** @see end */ + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionEndResponse + + /** @see end */ + fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) + + /** @see end */ + fun end(id: JsonValue, requestOptions: RequestOptions): SessionEndResponse = + end(id, SessionEndParams.none(), requestOptions) + + /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ + fun executeAgent(id: JsonValue): SessionExecuteAgentResponse = + executeAgent(id, SessionExecuteAgentParams.none()) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExecuteAgentResponse = executeAgent(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeAgent */ + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + ): SessionExecuteAgentResponse = executeAgent(id, params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExecuteAgentResponse + + /** @see executeAgent */ + fun executeAgent(params: SessionExecuteAgentParams): SessionExecuteAgentResponse = + executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + fun executeAgent(id: JsonValue, requestOptions: RequestOptions): SessionExecuteAgentResponse = + executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + + /** Extracts structured data from the current page using AI-powered analysis. */ + fun extract(id: JsonValue): SessionExtractResponse = extract(id, SessionExtractParams.none()) + + /** @see extract */ + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExtractResponse = extract(params.toBuilder().id(id).build(), requestOptions) + + /** @see extract */ + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + ): SessionExtractResponse = extract(id, params, RequestOptions.none()) + + /** @see extract */ + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionExtractResponse + + /** @see extract */ + fun extract(params: SessionExtractParams): SessionExtractResponse = + extract(params, RequestOptions.none()) + + /** @see extract */ + fun extract(id: JsonValue, requestOptions: RequestOptions): SessionExtractResponse = + extract(id, SessionExtractParams.none(), requestOptions) + + /** Navigates the browser to the specified URL. */ + fun navigate(id: JsonValue): SessionNavigateResponse = + navigate(id, SessionNavigateParams.none()) + + /** @see navigate */ + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionNavigateResponse = navigate(params.toBuilder().id(id).build(), requestOptions) + + /** @see navigate */ + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + ): SessionNavigateResponse = navigate(id, params, RequestOptions.none()) + + /** @see navigate */ + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionNavigateResponse + + /** @see navigate */ + fun navigate(params: SessionNavigateParams): SessionNavigateResponse = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + fun navigate(id: JsonValue, requestOptions: RequestOptions): SessionNavigateResponse = + navigate(id, SessionNavigateParams.none(), requestOptions) + + /** + * Identifies and returns available actions on the current page that match the given + * instruction. + */ + fun observe(id: JsonValue): SessionObserveResponse = observe(id, SessionObserveParams.none()) + + /** @see observe */ + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionObserveResponse = observe(params.toBuilder().id(id).build(), requestOptions) + + /** @see observe */ + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + ): SessionObserveResponse = observe(id, params, RequestOptions.none()) + + /** @see observe */ + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionObserveResponse + + /** @see observe */ + fun observe(params: SessionObserveParams): SessionObserveResponse = + observe(params, RequestOptions.none()) + + /** @see observe */ + fun observe(id: JsonValue, requestOptions: RequestOptions): SessionObserveResponse = + observe(id, SessionObserveParams.none(), requestOptions) + /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. @@ -54,6 +248,271 @@ interface SessionService { */ fun withOptions(modifier: Consumer): SessionService.WithRawResponse + /** + * Returns a raw HTTP response for `post /sessions/{id}/act`, but is otherwise the same as + * [SessionService.act]. + */ + @MustBeClosed + fun act(id: JsonValue): HttpResponseFor = + act(id, SessionActParams.none()) + + /** @see act */ + @MustBeClosed + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + act(params.toBuilder().id(id).build(), requestOptions) + + /** @see act */ + @MustBeClosed + fun act( + id: JsonValue, + params: SessionActParams = SessionActParams.none(), + ): HttpResponseFor = act(id, params, RequestOptions.none()) + + /** @see act */ + @MustBeClosed + fun act( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see act */ + @MustBeClosed + fun act(params: SessionActParams): HttpResponseFor = + act(params, RequestOptions.none()) + + /** @see act */ + @MustBeClosed + fun act( + id: JsonValue, + requestOptions: RequestOptions, + ): HttpResponseFor = act(id, SessionActParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/end`, but is otherwise the same as + * [SessionService.end]. + */ + @MustBeClosed + fun end(id: JsonValue): HttpResponseFor = + end(id, SessionEndParams.none()) + + /** @see end */ + @MustBeClosed + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + end(params.toBuilder().id(id).build(), requestOptions) + + /** @see end */ + @MustBeClosed + fun end( + id: JsonValue, + params: SessionEndParams = SessionEndParams.none(), + ): HttpResponseFor = end(id, params, RequestOptions.none()) + + /** @see end */ + @MustBeClosed + fun end( + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see end */ + @MustBeClosed + fun end(params: SessionEndParams): HttpResponseFor = + end(params, RequestOptions.none()) + + /** @see end */ + @MustBeClosed + fun end( + id: JsonValue, + requestOptions: RequestOptions, + ): HttpResponseFor = end(id, SessionEndParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/agentExecute`, but is otherwise the + * same as [SessionService.executeAgent]. + */ + @MustBeClosed + fun executeAgent(id: JsonValue): HttpResponseFor = + executeAgent(id, SessionExecuteAgentParams.none()) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + executeAgent(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + id: JsonValue, + params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + ): HttpResponseFor = + executeAgent(id, params, RequestOptions.none()) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + params: SessionExecuteAgentParams + ): HttpResponseFor = + executeAgent(params, RequestOptions.none()) + + /** @see executeAgent */ + @MustBeClosed + fun executeAgent( + id: JsonValue, + requestOptions: RequestOptions, + ): HttpResponseFor = + executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/extract`, but is otherwise the same + * as [SessionService.extract]. + */ + @MustBeClosed + fun extract(id: JsonValue): HttpResponseFor = + extract(id, SessionExtractParams.none()) + + /** @see extract */ + @MustBeClosed + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + extract(params.toBuilder().id(id).build(), requestOptions) + + /** @see extract */ + @MustBeClosed + fun extract( + id: JsonValue, + params: SessionExtractParams = SessionExtractParams.none(), + ): HttpResponseFor = extract(id, params, RequestOptions.none()) + + /** @see extract */ + @MustBeClosed + fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see extract */ + @MustBeClosed + fun extract(params: SessionExtractParams): HttpResponseFor = + extract(params, RequestOptions.none()) + + /** @see extract */ + @MustBeClosed + fun extract( + id: JsonValue, + requestOptions: RequestOptions, + ): HttpResponseFor = + extract(id, SessionExtractParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/navigate`, but is otherwise the same + * as [SessionService.navigate]. + */ + @MustBeClosed + fun navigate(id: JsonValue): HttpResponseFor = + navigate(id, SessionNavigateParams.none()) + + /** @see navigate */ + @MustBeClosed + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + navigate(params.toBuilder().id(id).build(), requestOptions) + + /** @see navigate */ + @MustBeClosed + fun navigate( + id: JsonValue, + params: SessionNavigateParams = SessionNavigateParams.none(), + ): HttpResponseFor = navigate(id, params, RequestOptions.none()) + + /** @see navigate */ + @MustBeClosed + fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see navigate */ + @MustBeClosed + fun navigate(params: SessionNavigateParams): HttpResponseFor = + navigate(params, RequestOptions.none()) + + /** @see navigate */ + @MustBeClosed + fun navigate( + id: JsonValue, + requestOptions: RequestOptions, + ): HttpResponseFor = + navigate(id, SessionNavigateParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /sessions/{id}/observe`, but is otherwise the same + * as [SessionService.observe]. + */ + @MustBeClosed + fun observe(id: JsonValue): HttpResponseFor = + observe(id, SessionObserveParams.none()) + + /** @see observe */ + @MustBeClosed + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + observe(params.toBuilder().id(id).build(), requestOptions) + + /** @see observe */ + @MustBeClosed + fun observe( + id: JsonValue, + params: SessionObserveParams = SessionObserveParams.none(), + ): HttpResponseFor = observe(id, params, RequestOptions.none()) + + /** @see observe */ + @MustBeClosed + fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see observe */ + @MustBeClosed + fun observe(params: SessionObserveParams): HttpResponseFor = + observe(params, RequestOptions.none()) + + /** @see observe */ + @MustBeClosed + fun observe( + id: JsonValue, + requestOptions: RequestOptions, + ): HttpResponseFor = + observe(id, SessionObserveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as * [SessionService.start]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index 2a983bb..467e9db 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -15,6 +15,18 @@ import com.browserbase.api.core.http.HttpResponseFor import com.browserbase.api.core.http.json import com.browserbase.api.core.http.parseable import com.browserbase.api.core.prepare +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionActResponse +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionEndResponse +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionExtractResponse +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionNavigateResponse +import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import java.util.function.Consumer @@ -31,6 +43,42 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO override fun withOptions(modifier: Consumer): SessionService = SessionServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) + override fun act(params: SessionActParams, requestOptions: RequestOptions): SessionActResponse = + // post /sessions/{id}/act + withRawResponse().act(params, requestOptions).parse() + + override fun end(params: SessionEndParams, requestOptions: RequestOptions): SessionEndResponse = + // post /sessions/{id}/end + withRawResponse().end(params, requestOptions).parse() + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): SessionExecuteAgentResponse = + // post /sessions/{id}/agentExecute + withRawResponse().executeAgent(params, requestOptions).parse() + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): SessionExtractResponse = + // post /sessions/{id}/extract + withRawResponse().extract(params, requestOptions).parse() + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): SessionNavigateResponse = + // post /sessions/{id}/navigate + withRawResponse().navigate(params, requestOptions).parse() + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): SessionObserveResponse = + // post /sessions/{id}/observe + withRawResponse().observe(params, requestOptions).parse() + override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -51,6 +99,174 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO clientOptions.toBuilder().apply(modifier::accept).build() ) + private val actHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun act( + params: SessionActParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "act") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { actHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val endHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun end( + params: SessionEndParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "end") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { endHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val executeAgentHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun executeAgent( + params: SessionExecuteAgentParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "agentExecute") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { executeAgentHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val extractHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun extract( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "extract") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { extractHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val navigateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun navigate( + params: SessionNavigateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "navigate") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { navigateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val observeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun observe( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("sessions", params._pathParam(0), "observe") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { observeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt new file mode 100644 index 0000000..4b81e39 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -0,0 +1,82 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionActParamsTest { + + @Test + fun create() { + SessionActParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + } + + @Test + fun pathParams() { + val params = SessionActParams.builder().id(JsonValue.from(mapOf())).build() + + assertThat(params._pathParam(0)).isEqualTo("[object Object]") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionActParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = SessionActParams.builder().id(JsonValue.from(mapOf())).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionActParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = SessionActParams.builder().id(JsonValue.from(mapOf())).build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt new file mode 100644 index 0000000..83f3fa4 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionActResponseTest { + + @Test + fun create() { + val sessionActResponse = SessionActResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionActResponse = SessionActResponse.builder().build() + + val roundtrippedSessionActResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionActResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionActResponse).isEqualTo(sessionActResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt new file mode 100644 index 0000000..514fc5e --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -0,0 +1,56 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionEndParamsTest { + + @Test + fun create() { + SessionEndParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .build() + } + + @Test + fun pathParams() { + val params = SessionEndParams.builder().id(JsonValue.from(mapOf())).build() + + assertThat(params._pathParam(0)).isEqualTo("[object Object]") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionEndParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = SessionEndParams.builder().id(JsonValue.from(mapOf())).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt new file mode 100644 index 0000000..30e45db --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionEndResponseTest { + + @Test + fun create() { + val sessionEndResponse = SessionEndResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionEndResponse = SessionEndResponse.builder().build() + + val roundtrippedSessionEndResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionEndResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionEndResponse).isEqualTo(sessionEndResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt new file mode 100644 index 0000000..90f1e1f --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt @@ -0,0 +1,85 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExecuteAgentParamsTest { + + @Test + fun create() { + SessionExecuteAgentParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + } + + @Test + fun pathParams() { + val params = + SessionExecuteAgentParams.builder().id(JsonValue.from(mapOf())).build() + + assertThat(params._pathParam(0)).isEqualTo("[object Object]") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionExecuteAgentParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionExecuteAgentParams.builder().id(JsonValue.from(mapOf())).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionExecuteAgentParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionExecuteAgentParams.builder().id(JsonValue.from(mapOf())).build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt new file mode 100644 index 0000000..0c28d46 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExecuteAgentResponseTest { + + @Test + fun create() { + val sessionExecuteAgentResponse = SessionExecuteAgentResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionExecuteAgentResponse = SessionExecuteAgentResponse.builder().build() + + val roundtrippedSessionExecuteAgentResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExecuteAgentResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExecuteAgentResponse).isEqualTo(sessionExecuteAgentResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt new file mode 100644 index 0000000..e631276 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -0,0 +1,82 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExtractParamsTest { + + @Test + fun create() { + SessionExtractParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + } + + @Test + fun pathParams() { + val params = SessionExtractParams.builder().id(JsonValue.from(mapOf())).build() + + assertThat(params._pathParam(0)).isEqualTo("[object Object]") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionExtractParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = SessionExtractParams.builder().id(JsonValue.from(mapOf())).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionExtractParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = SessionExtractParams.builder().id(JsonValue.from(mapOf())).build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt new file mode 100644 index 0000000..04bed64 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExtractResponseTest { + + @Test + fun create() { + val sessionExtractResponse = SessionExtractResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionExtractResponse = SessionExtractResponse.builder().build() + + val roundtrippedSessionExtractResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExtractResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExtractResponse).isEqualTo(sessionExtractResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt new file mode 100644 index 0000000..6d8a60d --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -0,0 +1,85 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionNavigateParamsTest { + + @Test + fun create() { + SessionNavigateParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + } + + @Test + fun pathParams() { + val params = + SessionNavigateParams.builder().id(JsonValue.from(mapOf())).build() + + assertThat(params._pathParam(0)).isEqualTo("[object Object]") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionNavigateParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionNavigateParams.builder().id(JsonValue.from(mapOf())).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionNavigateParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionNavigateParams.builder().id(JsonValue.from(mapOf())).build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt new file mode 100644 index 0000000..6d62909 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionNavigateResponseTest { + + @Test + fun create() { + val sessionNavigateResponse = SessionNavigateResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionNavigateResponse = SessionNavigateResponse.builder().build() + + val roundtrippedSessionNavigateResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionNavigateResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionNavigateResponse).isEqualTo(sessionNavigateResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt new file mode 100644 index 0000000..8943f1d --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -0,0 +1,82 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionObserveParamsTest { + + @Test + fun create() { + SessionObserveParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + } + + @Test + fun pathParams() { + val params = SessionObserveParams.builder().id(JsonValue.from(mapOf())).build() + + assertThat(params._pathParam(0)).isEqualTo("[object Object]") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionObserveParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = SessionObserveParams.builder().id(JsonValue.from(mapOf())).build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionObserveParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = SessionObserveParams.builder().id(JsonValue.from(mapOf())).build() + + val body = params._body() + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt new file mode 100644 index 0000000..b597689 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionObserveResponseTest { + + @Test + fun create() { + val sessionObserveResponse = SessionObserveResponse.builder().build() + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionObserveResponse = SessionObserveResponse.builder().build() + + val roundtrippedSessionObserveResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionObserveResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionObserveResponse).isEqualTo(sessionObserveResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 57ff039..dba84aa 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -5,6 +5,12 @@ package com.browserbase.api.services.async import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -13,6 +19,173 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) internal class SessionServiceAsyncTest { + @Disabled("Prism tests are disabled") + @Test + fun act() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.act( + SessionActParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun end() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.end( + SessionEndParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun executeAgent() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.executeAgent( + SessionExecuteAgentParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun extract() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.extract( + SessionExtractParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun navigate() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.navigate( + SessionNavigateParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun observe() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.observe( + SessionObserveParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + @Disabled("Prism tests are disabled") @Test fun start() { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index c782cd2..03853cd 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -5,6 +5,12 @@ package com.browserbase.api.services.blocking import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionEndParams +import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExtractParams +import com.browserbase.api.models.sessions.SessionNavigateParams +import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -13,6 +19,167 @@ import org.junit.jupiter.api.extension.ExtendWith @ExtendWith(TestServerExtension::class) internal class SessionServiceTest { + @Disabled("Prism tests are disabled") + @Test + fun act() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.act( + SessionActParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun end() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.end( + SessionEndParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun executeAgent() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.executeAgent( + SessionExecuteAgentParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun extract() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.extract( + SessionExtractParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun navigate() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.navigate( + SessionNavigateParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + response.validate() + } + + @Disabled("Prism tests are disabled") + @Test + fun observe() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.observe( + SessionObserveParams.builder() + .id(JsonValue.from(mapOf())) + .xLanguage(JsonValue.from(mapOf())) + .xSdkVersion(JsonValue.from(mapOf())) + .xSentAt(JsonValue.from(mapOf())) + .xStreamResponse(JsonValue.from(mapOf())) + .body(JsonValue.from(mapOf())) + .build() + ) + + response.validate() + } + @Disabled("Prism tests are disabled") @Test fun start() { From 48fc525c4e27a044814081dd556b4238b9ff7783 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:20:37 +0000 Subject: [PATCH 029/164] feat(api): manual updates --- .stats.yml | 6 +- README.md | 104 +- .../main/kotlin/stagehand.publish.gradle.kts | 2 +- .../api/models/sessions/SessionActParams.kt | 1547 +++- .../api/models/sessions/SessionActResponse.kt | 731 +- .../api/models/sessions/SessionEndParams.kt | 347 +- .../api/models/sessions/SessionEndResponse.kt | 193 +- .../sessions/SessionExecuteAgentParams.kt | 269 - .../sessions/SessionExecuteAgentResponse.kt | 118 - .../models/sessions/SessionExecuteParams.kt | 1403 +++ .../models/sessions/SessionExecuteResponse.kt | 1775 ++++ .../models/sessions/SessionExtractParams.kt | 1069 ++- .../models/sessions/SessionExtractResponse.kt | 395 +- .../models/sessions/SessionNavigateParams.kt | 1074 ++- .../sessions/SessionNavigateResponse.kt | 392 +- .../models/sessions/SessionObserveParams.kt | 907 +- .../models/sessions/SessionObserveResponse.kt | 439 +- .../api/models/sessions/SessionStartParams.kt | 7696 ++++++++++++++++- .../models/sessions/SessionStartResponse.kt | 428 +- .../api/services/async/SessionServiceAsync.kt | 323 +- .../services/async/SessionServiceAsyncImpl.kt | 72 +- .../api/services/blocking/SessionService.kt | 295 +- .../services/blocking/SessionServiceImpl.kt | 72 +- .../models/sessions/SessionActParamsTest.kt | 122 +- .../models/sessions/SessionActResponseTest.kt | 73 +- .../models/sessions/SessionEndParamsTest.kt | 38 +- .../models/sessions/SessionEndResponseTest.kt | 8 +- .../sessions/SessionExecuteAgentParamsTest.kt | 85 - .../SessionExecuteAgentResponseTest.kt | 30 - .../sessions/SessionExecuteParamsTest.kt | 199 + .../sessions/SessionExecuteResponseTest.kt | 151 + .../sessions/SessionExtractParamsTest.kt | 115 +- .../sessions/SessionExtractResponseTest.kt | 32 +- .../sessions/SessionNavigateParamsTest.kt | 102 +- .../sessions/SessionNavigateResponseTest.kt | 33 +- .../sessions/SessionObserveParamsTest.kt | 94 +- .../sessions/SessionObserveResponseTest.kt | 52 +- .../models/sessions/SessionStartParamsTest.kt | 607 +- .../sessions/SessionStartResponseTest.kt | 31 +- .../api/services/ErrorHandlingTest.kt | 547 +- .../api/services/ServiceParamsTest.kt | 35 +- .../services/async/SessionServiceAsyncTest.kt | 290 +- .../services/blocking/SessionServiceTest.kt | 290 +- 43 files changed, 20977 insertions(+), 1614 deletions(-) delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt delete mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt diff --git a/.stats.yml b/.stats.yml index c436ede..87bd24b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-c1a6f03afe5d6823c198e5ac476fb688dacc783dae1fefdf6bf142084e298e16.yml -openapi_spec_hash: d20e8f697ce8d5bb80295fc1e8ce02e8 -config_hash: e457d704d820df5d25acfd379169f132 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-349e1b0f6291eedd731c1660155a50adcb3424fb8cd9e17bbdc0939ff3bbffcd.yml +openapi_spec_hash: 456b593ea71d72bc31a6338a25363e9f +config_hash: 5f6b5ec6e84fb01932ba87c6a9623d9b diff --git a/README.md b/README.md index 1bab387..019da3c 100644 --- a/README.md +++ b/README.md @@ -48,14 +48,18 @@ This library requires Java 8 or later. ```java import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); -SessionStartResponse response = client.sessions().start(); +SessionActParams params = SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build(); +SessionActResponse response = client.sessions().act(params); ``` ## Client configuration @@ -132,7 +136,7 @@ The `withOptions()` method does not affect the original client or service. To send a request to the Stagehand API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. -For example, `client.sessions().start(...)` should be called with an instance of `SessionStartParams`, and it will return an instance of `SessionStartResponse`. +For example, `client.sessions().act(...)` should be called with an instance of `SessionActParams`, and it will return an instance of `SessionActResponse`. ## Immutability @@ -149,15 +153,19 @@ The default client is synchronous. To switch to asynchronous execution, call the ```java import com.browserbase.api.client.StagehandClient; import com.browserbase.api.client.okhttp.StagehandOkHttpClient; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; import java.util.concurrent.CompletableFuture; // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClient client = StagehandOkHttpClient.fromEnv(); -CompletableFuture response = client.async().sessions().start(); +SessionActParams params = SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build(); +CompletableFuture response = client.async().sessions().act(params); ``` Or create an asynchronous client from the beginning: @@ -165,15 +173,19 @@ Or create an asynchronous client from the beginning: ```java import com.browserbase.api.client.StagehandClientAsync; import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; import java.util.concurrent.CompletableFuture; // Configures using the `stagehand.browserbaseApiKey`, `stagehand.browserbaseProjectId`, `stagehand.modelApiKey` and `stagehand.baseUrl` system properties // Or configures using the `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`, `MODEL_API_KEY` and `STAGEHAND_BASE_URL` environment variables StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); -CompletableFuture response = client.sessions().start(); +SessionActParams params = SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build(); +CompletableFuture response = client.sessions().act(params); ``` The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. @@ -187,10 +199,14 @@ To access this data, prefix any HTTP method call on a client or service with `wi ```java import com.browserbase.api.core.http.Headers; import com.browserbase.api.core.http.HttpResponseFor; -import com.browserbase.api.models.sessions.SessionStartParams; -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActParams; +import com.browserbase.api.models.sessions.SessionActResponse; -HttpResponseFor response = client.sessions().withRawResponse().start(); +SessionActParams params = SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build(); +HttpResponseFor response = client.sessions().withRawResponse().act(params); int statusCode = response.statusCode(); Headers headers = response.headers(); @@ -199,9 +215,9 @@ Headers headers = response.headers(); You can still deserialize the response into an instance of a Java class if needed: ```java -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActResponse; -SessionStartResponse parsedResponse = response.parse(); +SessionActResponse parsedResponse = response.parse(); ``` ## Error handling @@ -297,9 +313,11 @@ Requests time out after 1 minute by default. To set a custom timeout, configure the method call using the `timeout` method: ```java -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActResponse; -SessionStartResponse response = client.sessions().start(RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()); +SessionActResponse response = client.sessions().act( + params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() +); ``` Or configure the default for all method calls at the client level: @@ -402,9 +420,9 @@ To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQu ```java import com.browserbase.api.core.JsonValue; -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; -SessionStartParams params = SessionStartParams.builder() +SessionActParams params = SessionActParams.builder() .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) @@ -413,12 +431,29 @@ SessionStartParams params = SessionStartParams.builder() These can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods. +To set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class: + +```java +import com.browserbase.api.core.JsonValue; +import com.browserbase.api.models.sessions.SessionActParams; + +SessionActParams params = SessionActParams.builder() + .options(SessionActParams.Options.builder() + .putAdditionalProperty("secretProperty", JsonValue.from("42")) + .build()) + .build(); +``` + +These properties can be accessed on the nested built object later using the `_additionalProperties()` method. + To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) object to its setter: ```java -import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionActParams; -SessionStartParams params = SessionStartParams.builder().build(); +SessionActParams params = SessionActParams.builder() + .input("Click the login button") + .build(); ``` The most straightforward way to create a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) is using its `from(...)` method: @@ -467,9 +502,9 @@ To forcibly omit a required parameter or property, pass [`JsonMissing`](stagehan ```java import com.browserbase.api.core.JsonMissing; import com.browserbase.api.models.sessions.SessionActParams; -import com.browserbase.api.models.sessions.SessionStartParams; -SessionStartParams params = SessionActParams.builder() +SessionActParams params = SessionActParams.builder() + .input("Click the login button") .id(JsonMissing.of()) .build(); ``` @@ -482,7 +517,7 @@ To access undocumented response properties, call the `_additionalProperties()` m import com.browserbase.api.core.JsonValue; import java.util.Map; -Map additionalProperties = client.sessions().start(params)._additionalProperties(); +Map additionalProperties = client.sessions().act(params)._additionalProperties(); JsonValue secretPropertyValue = additionalProperties.get("secretProperty"); String result = secretPropertyValue.accept(new JsonValue.Visitor<>() { @@ -510,21 +545,22 @@ To access a property's raw JSON value, which may be undocumented, call its `_` p ```java import com.browserbase.api.core.JsonField; +import com.browserbase.api.models.sessions.SessionActParams; import java.util.Optional; -JsonField field = client.sessions().start(params)._field(); +JsonField input = client.sessions().act(params)._input(); -if (field.isMissing()) { +if (input.isMissing()) { // The property is absent from the JSON response -} else if (field.isNull()) { +} else if (input.isNull()) { // The property was set to literal null } else { // Check if value was provided as a string // Other methods include `asNumber()`, `asBoolean()`, etc. - Optional jsonString = field.asString(); + Optional jsonString = input.asString(); // Try to deserialize into a custom type - MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class); + MyClass myObject = input.asUnknown().orElseThrow().convert(MyClass.class); } ``` @@ -537,17 +573,19 @@ By default, the SDK will not throw an exception in this case. It will throw [`St If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: ```java -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActResponse; -SessionStartResponse response = client.sessions().start(params).validate(); +SessionActResponse response = client.sessions().act(params).validate(); ``` Or configure the method call to validate the response using the `responseValidation` method: ```java -import com.browserbase.api.models.sessions.SessionStartResponse; +import com.browserbase.api.models.sessions.SessionActResponse; -SessionStartResponse response = client.sessions().start(RequestOptions.builder().responseValidation(true).build()); +SessionActResponse response = client.sessions().act( + params, RequestOptions.builder().responseValidation(true).build() +); ``` Or configure the default for all method calls at the client level: diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index 7b0ce3f..796aad4 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -10,7 +10,7 @@ configure { pom { name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + description.set("Stagehand SDK for AI browser automation [ALPHA].") url.set("https://docs.stagehand.dev") licenses { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 9992e1f..7e98b5d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -2,11 +2,36 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,27 +39,75 @@ import kotlin.jvm.optionals.getOrNull /** Executes a browser action using natural language instructions or a predefined Action object. */ class SessionActParams private constructor( - private val id: JsonValue?, - private val xLanguage: JsonValue?, - private val xSdkVersion: JsonValue?, - private val xSentAt: JsonValue?, - private val xStreamResponse: JsonValue?, - private val body: JsonValue, + private val id: String?, + private val xLanguage: XLanguage?, + private val xSdkVersion: String?, + private val xSentAt: OffsetDateTime?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun id(): Optional = Optional.ofNullable(id) + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun body(): JsonValue = body + /** + * Natural language instruction or Action object + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun input(): Input = body.input() + + /** + * Target frame ID for the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _input(): JsonField = body._input() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -46,21 +119,26 @@ private constructor( companion object { - @JvmStatic fun none(): SessionActParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionActParams]. */ + /** + * Returns a mutable builder for constructing an instance of [SessionActParams]. + * + * The following fields are required: + * ```java + * .input() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionActParams]. */ class Builder internal constructor() { - private var id: JsonValue? = null - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null - private var body: JsonValue = JsonMissing.of() + private var id: String? = null + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -71,40 +149,111 @@ private constructor( xSdkVersion = sessionActParams.xSdkVersion xSentAt = sessionActParams.xSentAt xStreamResponse = sessionActParams.xStreamResponse - body = sessionActParams.body + body = sessionActParams.body.toBuilder() additionalHeaders = sessionActParams.additionalHeaders.toBuilder() additionalQueryParams = sessionActParams.additionalQueryParams.toBuilder() } - fun id(id: JsonValue?) = apply { this.id = id } + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } /** Alias for calling [Builder.id] with `id.orElse(null)`. */ - fun id(id: Optional) = id(id.getOrNull()) + fun id(id: Optional) = id(id.getOrNull()) - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse } /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = + fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - fun body(body: JsonValue) = apply { this.body = body } + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [input] + * - [frameId] + * - [options] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Natural language instruction or Action object */ + fun input(input: Input) = apply { body.input(input) } + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [Input] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField) = apply { body.input(input) } + + /** Alias for calling [input] with `Input.ofString(string)`. */ + fun input(string: String) = apply { body.input(string) } + + /** Alias for calling [input] with `Input.ofAction(action)`. */ + fun input(action: Input.ActionInput) = apply { body.input(action) } + + /** Target frame ID for the action */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -208,6 +357,13 @@ private constructor( * Returns an immutable instance of [SessionActParams]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): SessionActParams = SessionActParams( @@ -216,24 +372,1341 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, - body, + body.build(), additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): JsonValue = body + fun _body(): Body = body fun _pathParam(index: Int): String = when (index) { - 0 -> id?.toString() ?: "" + 0 -> id ?: "" else -> "" } - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val input: JsonField, + private val frameId: JsonField, + private val options: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + ) : this(input, frameId, options, mutableMapOf()) + + /** + * Natural language instruction or Action object + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun input(): Input = input.getRequired("input") + + /** + * Target frame ID for the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .input() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var input: JsonField? = null + private var frameId: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + input = body.input + frameId = body.frameId + options = body.options + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Natural language instruction or Action object */ + fun input(input: Input) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [Input] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun input(input: JsonField) = apply { this.input = input } + + /** Alias for calling [input] with `Input.ofString(string)`. */ + fun input(string: String) = input(Input.ofString(string)) + + /** Alias for calling [input] with `Input.ofAction(action)`. */ + fun input(action: Input.ActionInput) = input(Input.ofAction(action)) + + /** Target frame ID for the action */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("input", input), + frameId, + options, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + input().validate() + frameId() + options().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (input.asKnown().getOrNull()?.validity() ?: 0) + + (if (frameId.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + input == other.input && + frameId == other.frameId && + options == other.options && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(input, frameId, options, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{input=$input, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" + } + + /** Natural language instruction or Action object */ + @JsonDeserialize(using = Input.Deserializer::class) + @JsonSerialize(using = Input.Serializer::class) + class Input + private constructor( + private val string: String? = null, + private val action: ActionInput? = null, + private val _json: JsonValue? = null, + ) { + + fun string(): Optional = Optional.ofNullable(string) + + /** Action object returned by observe and used by act */ + fun action(): Optional = Optional.ofNullable(action) + + fun isString(): Boolean = string != null + + fun isAction(): Boolean = action != null + + fun asString(): String = string.getOrThrow("string") + + /** Action object returned by observe and used by act */ + fun asAction(): ActionInput = action.getOrThrow("action") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + action != null -> visitor.visitAction(action) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Input = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitAction(action: ActionInput) { + action.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitString(string: String) = 1 + + override fun visitAction(action: ActionInput) = action.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Input && string == other.string && action == other.action + } + + override fun hashCode(): Int = Objects.hash(string, action) + + override fun toString(): String = + when { + string != null -> "Input{string=$string}" + action != null -> "Input{action=$action}" + _json != null -> "Input{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Input") + } + + companion object { + + @JvmStatic fun ofString(string: String) = Input(string = string) + + /** Action object returned by observe and used by act */ + @JvmStatic fun ofAction(action: ActionInput) = Input(action = action) + } + + /** An interface that defines how to map each variant of [Input] to a value of type [T]. */ + interface Visitor { + + fun visitString(string: String): T + + /** Action object returned by observe and used by act */ + fun visitAction(action: ActionInput): T + + /** + * Maps an unknown variant of [Input] to a value of type [T]. + * + * An instance of [Input] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Input: $json") + } + } + + internal class Deserializer : BaseDeserializer(Input::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Input { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Input(action = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Input(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from array). + 0 -> Input(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Input::class) { + + override fun serialize( + value: Input, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.action != null -> generator.writeObject(value.action) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Input") + } + } + } + + /** Action object returned by observe and used by act */ + class ActionInput + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val selector: JsonField, + private val arguments: JsonField>, + private val method: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField> = JsonMissing.of(), + @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), + ) : this(description, selector, arguments, method, mutableMapOf()) + + /** + * Human-readable description of the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun description(): String = description.getRequired("description") + + /** + * CSS selector or XPath for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun selector(): String = selector.getRequired("selector") + + /** + * Arguments to pass to the method + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun arguments(): Optional> = arguments.getOptional("arguments") + + /** + * The method to execute (click, fill, etc.) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun method(): Optional = method.getOptional("method") + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [arguments]. + * + * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("arguments") + @ExcludeMissing + fun _arguments(): JsonField> = arguments + + /** + * Returns the raw JSON value of [method]. + * + * Unlike [method], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ActionInput]. + * + * The following fields are required: + * ```java + * .description() + * .selector() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ActionInput]. */ + class Builder internal constructor() { + + private var description: JsonField? = null + private var selector: JsonField? = null + private var arguments: JsonField>? = null + private var method: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(actionInput: ActionInput) = apply { + description = actionInput.description + selector = actionInput.selector + arguments = actionInput.arguments.map { it.toMutableList() } + method = actionInput.method + additionalProperties = actionInput.additionalProperties.toMutableMap() + } + + /** Human-readable description of the action */ + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** CSS selector or XPath for the element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** Arguments to pass to the method */ + fun arguments(arguments: List) = arguments(JsonField.of(arguments)) + + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun arguments(arguments: JsonField>) = apply { + this.arguments = arguments.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [arguments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addArgument(argument: String) = apply { + arguments = + (arguments ?: JsonField.of(mutableListOf())).also { + checkKnown("arguments", it).add(argument) + } + } + + /** The method to execute (click, fill, etc.) */ + fun method(method: String) = method(JsonField.of(method)) + + /** + * Sets [Builder.method] to an arbitrary JSON value. + * + * You should usually call [Builder.method] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun method(method: JsonField) = apply { this.method = method } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ActionInput]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .description() + * .selector() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ActionInput = + ActionInput( + checkRequired("description", description), + checkRequired("selector", selector), + (arguments ?: JsonMissing.of()).map { it.toImmutable() }, + method, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ActionInput = apply { + if (validated) { + return@apply + } + + description() + selector() + arguments() + method() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (description.asKnown().isPresent) 1 else 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (arguments.asKnown().getOrNull()?.size ?: 0) + + (if (method.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ActionInput && + description == other.description && + selector == other.selector && + arguments == other.arguments && + method == other.method && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(description, selector, arguments, method, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ActionInput{description=$description, selector=$selector, arguments=$arguments, method=$method, additionalProperties=$additionalProperties}" + } + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val timeout: JsonField, + private val variables: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + @JsonProperty("variables") + @ExcludeMissing + variables: JsonField = JsonMissing.of(), + ) : this(model, timeout, variables, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Timeout in ms for the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * Variables to substitute in the action instruction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun variables(): Optional = variables.getOptional("variables") + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + /** + * Returns the raw JSON value of [variables]. + * + * Unlike [variables], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("variables") + @ExcludeMissing + fun _variables(): JsonField = variables + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var variables: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + model = options.model + timeout = options.timeout + variables = options.variables + additionalProperties = options.additionalProperties.toMutableMap() + } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) + + /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ + fun model(unionMember1: ModelConfig.UnionMember1) = + model(ModelConfig.ofUnionMember1(unionMember1)) + + /** Timeout in ms for the action */ + fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + /** Variables to substitute in the action instruction */ + fun variables(variables: Variables) = variables(JsonField.of(variables)) + + /** + * Sets [Builder.variables] to an arbitrary JSON value. + * + * You should usually call [Builder.variables] with a well-typed [Variables] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun variables(variables: JsonField) = apply { this.variables = variables } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(model, timeout, variables, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + model().ifPresent { it.validate() } + timeout() + variables().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + (variables.asKnown().getOrNull()?.validity() ?: 0) + + /** Variables to substitute in the action instruction */ + class Variables + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Variables]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Variables]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(variables: Variables) = apply { + additionalProperties = variables.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Variables]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Variables = Variables(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Variables = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Variables && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Variables{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + model == other.model && + timeout == other.timeout && + variables == other.variables && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, timeout, variables, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{model=$model, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" + } + + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt index 57b8827..bfa1f65 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -2,20 +2,63 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull class SessionActResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -31,20 +74,52 @@ private constructor(private val additionalProperties: MutableMap? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionActResponse: SessionActResponse) = apply { + data = sessionActResponse.data + success = sessionActResponse.success additionalProperties = sessionActResponse.additionalProperties.toMutableMap() } + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -68,8 +143,21 @@ private constructor(private val additionalProperties: MutableMap, + private val actionId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("result") @ExcludeMissing result: JsonField = JsonMissing.of(), + @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), + ) : this(result, actionId, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun result(): Result = result.getRequired("result") + + /** + * Action ID for tracking + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun actionId(): Optional = actionId.getOptional("actionId") + + /** + * Returns the raw JSON value of [result]. + * + * Unlike [result], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonField = result + + /** + * Returns the raw JSON value of [actionId]. + * + * Unlike [actionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actionId") @ExcludeMissing fun _actionId(): JsonField = actionId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .result() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var result: JsonField? = null + private var actionId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + result = data.result + actionId = data.actionId + additionalProperties = data.additionalProperties.toMutableMap() + } + + fun result(result: Result) = result(JsonField.of(result)) + + /** + * Sets [Builder.result] to an arbitrary JSON value. + * + * You should usually call [Builder.result] with a well-typed [Result] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun result(result: JsonField) = apply { this.result = result } + + /** Action ID for tracking */ + fun actionId(actionId: String) = actionId(JsonField.of(actionId)) + + /** + * Sets [Builder.actionId] to an arbitrary JSON value. + * + * You should usually call [Builder.actionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actionId(actionId: JsonField) = apply { this.actionId = actionId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .result() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Data = + Data(checkRequired("result", result), actionId, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + result().validate() + actionId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (result.asKnown().getOrNull()?.validity() ?: 0) + + (if (actionId.asKnown().isPresent) 1 else 0) + + class Result + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val actionDescription: JsonField, + private val actions: JsonField>, + private val message: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("actionDescription") + @ExcludeMissing + actionDescription: JsonField = JsonMissing.of(), + @JsonProperty("actions") + @ExcludeMissing + actions: JsonField> = JsonMissing.of(), + @JsonProperty("message") + @ExcludeMissing + message: JsonField = JsonMissing.of(), + @JsonProperty("success") + @ExcludeMissing + success: JsonField = JsonMissing.of(), + ) : this(actionDescription, actions, message, success, mutableMapOf()) + + /** + * Description of the action that was performed + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun actionDescription(): String = actionDescription.getRequired("actionDescription") + + /** + * List of actions that were executed + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun actions(): List = actions.getRequired("actions") + + /** + * Human-readable result message + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun message(): String = message.getRequired("message") + + /** + * Whether the action completed successfully + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun success(): Boolean = success.getRequired("success") + + /** + * Returns the raw JSON value of [actionDescription]. + * + * Unlike [actionDescription], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("actionDescription") + @ExcludeMissing + fun _actionDescription(): JsonField = actionDescription + + /** + * Returns the raw JSON value of [actions]. + * + * Unlike [actions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actions") + @ExcludeMissing + fun _actions(): JsonField> = actions + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Result]. + * + * The following fields are required: + * ```java + * .actionDescription() + * .actions() + * .message() + * .success() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Result]. */ + class Builder internal constructor() { + + private var actionDescription: JsonField? = null + private var actions: JsonField>? = null + private var message: JsonField? = null + private var success: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(result: Result) = apply { + actionDescription = result.actionDescription + actions = result.actions.map { it.toMutableList() } + message = result.message + success = result.success + additionalProperties = result.additionalProperties.toMutableMap() + } + + /** Description of the action that was performed */ + fun actionDescription(actionDescription: String) = + actionDescription(JsonField.of(actionDescription)) + + /** + * Sets [Builder.actionDescription] to an arbitrary JSON value. + * + * You should usually call [Builder.actionDescription] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun actionDescription(actionDescription: JsonField) = apply { + this.actionDescription = actionDescription + } + + /** List of actions that were executed */ + fun actions(actions: List) = actions(JsonField.of(actions)) + + /** + * Sets [Builder.actions] to an arbitrary JSON value. + * + * You should usually call [Builder.actions] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun actions(actions: JsonField>) = apply { + this.actions = actions.map { it.toMutableList() } + } + + /** + * Adds a single [Action] to [actions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAction(action: Action) = apply { + actions = + (actions ?: JsonField.of(mutableListOf())).also { + checkKnown("actions", it).add(action) + } + } + + /** Human-readable result message */ + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** Whether the action completed successfully */ + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Result]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .actionDescription() + * .actions() + * .message() + * .success() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Result = + Result( + checkRequired("actionDescription", actionDescription), + checkRequired("actions", actions).map { it.toImmutable() }, + checkRequired("message", message), + checkRequired("success", success), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Result = apply { + if (validated) { + return@apply + } + + actionDescription() + actions().forEach { it.validate() } + message() + success() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (actionDescription.asKnown().isPresent) 1 else 0) + + (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (message.asKnown().isPresent) 1 else 0) + + (if (success.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Result && + actionDescription == other.actionDescription && + actions == other.actions && + message == other.message && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(actionDescription, actions, message, success, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Result{actionDescription=$actionDescription, actions=$actions, message=$message, success=$success, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + result == other.result && + actionId == other.actionId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(result, actionId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" + } + + class Success @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is SessionActResponse && additionalProperties == other.additionalProperties + return other is SessionActResponse && + data == other.data && + success == other.success && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(data, success, additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "SessionActResponse{additionalProperties=$additionalProperties}" + override fun toString() = + "SessionActResponse{data=$data, success=$success, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index 02f9cb0..90a656f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -2,11 +2,17 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum +import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,25 +20,30 @@ import kotlin.jvm.optionals.getOrNull /** Terminates the browser session and releases all associated resources. */ class SessionEndParams private constructor( - private val id: JsonValue?, - private val xLanguage: JsonValue?, - private val xSdkVersion: JsonValue?, - private val xSentAt: JsonValue?, - private val xStreamResponse: JsonValue?, + private val id: String?, + private val xLanguage: XLanguage?, + private val xSdkVersion: String?, + private val xSentAt: OffsetDateTime?, + private val xStreamResponse: XStreamResponse?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun id(): Optional = Optional.ofNullable(id) + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) /** Additional body properties to send with the request. */ fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -56,11 +67,11 @@ private constructor( /** A builder for [SessionEndParams]. */ class Builder internal constructor() { - private var id: JsonValue? = null - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null + private var id: String? = null + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() private var additionalBodyProperties: MutableMap = mutableMapOf() @@ -77,32 +88,37 @@ private constructor( additionalBodyProperties = sessionEndParams.additionalBodyProperties.toMutableMap() } - fun id(id: JsonValue?) = apply { this.id = id } + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } /** Alias for calling [Builder.id] with `id.orElse(null)`. */ - fun id(id: Optional) = id(id.getOrNull()) + fun id(id: Optional) = id(id.getOrNull()) - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse } /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = + fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { @@ -248,14 +264,291 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> id?.toString() ?: "" + 0 -> id ?: "" else -> "" } - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt index 970e0fd..3bed0ac 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -2,20 +2,45 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import kotlin.jvm.optionals.getOrNull class SessionEndResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val success: JsonField, + private val additionalProperties: MutableMap, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of() + ) : this(success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -31,20 +56,39 @@ private constructor(private val additionalProperties: MutableMap? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionEndResponse: SessionEndResponse) = apply { + success = sessionEndResponse.success additionalProperties = sessionEndResponse.additionalProperties.toMutableMap() } + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -68,8 +112,19 @@ private constructor(private val additionalProperties: MutableMap) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is SessionEndResponse && additionalProperties == other.additionalProperties + return other is SessionEndResponse && + success == other.success && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(success, additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "SessionEndResponse{additionalProperties=$additionalProperties}" + override fun toString() = + "SessionEndResponse{success=$success, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt deleted file mode 100644 index eca9552..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParams.kt +++ /dev/null @@ -1,269 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.JsonMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.Params -import com.browserbase.api.core.http.Headers -import com.browserbase.api.core.http.QueryParams -import java.util.Objects -import java.util.Optional -import kotlin.jvm.optionals.getOrNull - -/** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ -class SessionExecuteAgentParams -private constructor( - private val id: JsonValue?, - private val xLanguage: JsonValue?, - private val xSdkVersion: JsonValue?, - private val xSentAt: JsonValue?, - private val xStreamResponse: JsonValue?, - private val body: JsonValue, - private val additionalHeaders: Headers, - private val additionalQueryParams: QueryParams, -) : Params { - - fun id(): Optional = Optional.ofNullable(id) - - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - - fun body(): JsonValue = body - - /** Additional headers to send with the request. */ - fun _additionalHeaders(): Headers = additionalHeaders - - /** Additional query param to send with the request. */ - fun _additionalQueryParams(): QueryParams = additionalQueryParams - - fun toBuilder() = Builder().from(this) - - companion object { - - @JvmStatic fun none(): SessionExecuteAgentParams = builder().build() - - /** - * Returns a mutable builder for constructing an instance of [SessionExecuteAgentParams]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionExecuteAgentParams]. */ - class Builder internal constructor() { - - private var id: JsonValue? = null - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null - private var body: JsonValue = JsonMissing.of() - private var additionalHeaders: Headers.Builder = Headers.builder() - private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - - @JvmSynthetic - internal fun from(sessionExecuteAgentParams: SessionExecuteAgentParams) = apply { - id = sessionExecuteAgentParams.id - xLanguage = sessionExecuteAgentParams.xLanguage - xSdkVersion = sessionExecuteAgentParams.xSdkVersion - xSentAt = sessionExecuteAgentParams.xSentAt - xStreamResponse = sessionExecuteAgentParams.xStreamResponse - body = sessionExecuteAgentParams.body - additionalHeaders = sessionExecuteAgentParams.additionalHeaders.toBuilder() - additionalQueryParams = sessionExecuteAgentParams.additionalQueryParams.toBuilder() - } - - fun id(id: JsonValue?) = apply { this.id = id } - - /** Alias for calling [Builder.id] with `id.orElse(null)`. */ - fun id(id: Optional) = id(id.getOrNull()) - - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { - this.xStreamResponse = xStreamResponse - } - - /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = - xStreamResponse(xStreamResponse.getOrNull()) - - fun body(body: JsonValue) = apply { this.body = body } - - fun additionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun additionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.clear() - putAllAdditionalHeaders(additionalHeaders) - } - - fun putAdditionalHeader(name: String, value: String) = apply { - additionalHeaders.put(name, value) - } - - fun putAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.put(name, values) - } - - fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.putAll(additionalHeaders) - } - - fun replaceAdditionalHeaders(name: String, value: String) = apply { - additionalHeaders.replace(name, value) - } - - fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { - additionalHeaders.replace(name, values) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { - this.additionalHeaders.replaceAll(additionalHeaders) - } - - fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } - - fun removeAllAdditionalHeaders(names: Set) = apply { - additionalHeaders.removeAll(names) - } - - fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun additionalQueryParams(additionalQueryParams: Map>) = apply { - this.additionalQueryParams.clear() - putAllAdditionalQueryParams(additionalQueryParams) - } - - fun putAdditionalQueryParam(key: String, value: String) = apply { - additionalQueryParams.put(key, value) - } - - fun putAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.put(key, values) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.putAll(additionalQueryParams) - } - - fun replaceAdditionalQueryParams(key: String, value: String) = apply { - additionalQueryParams.replace(key, value) - } - - fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { - additionalQueryParams.replace(key, values) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = - apply { - this.additionalQueryParams.replaceAll(additionalQueryParams) - } - - fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } - - fun removeAllAdditionalQueryParams(keys: Set) = apply { - additionalQueryParams.removeAll(keys) - } - - /** - * Returns an immutable instance of [SessionExecuteAgentParams]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionExecuteAgentParams = - SessionExecuteAgentParams( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders.build(), - additionalQueryParams.build(), - ) - } - - fun _body(): JsonValue = body - - fun _pathParam(index: Int): String = - when (index) { - 0 -> id?.toString() ?: "" - else -> "" - } - - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() - - override fun _queryParams(): QueryParams = additionalQueryParams - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionExecuteAgentParams && - id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && - xSentAt == other.xSentAt && - xStreamResponse == other.xStreamResponse && - body == other.body && - additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams - } - - override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) - - override fun toString() = - "SessionExecuteAgentParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt deleted file mode 100644 index 700a7ba..0000000 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponse.kt +++ /dev/null @@ -1,118 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonValue -import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter -import com.fasterxml.jackson.annotation.JsonCreator -import java.util.Collections -import java.util.Objects - -class SessionExecuteAgentResponse -@JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { - - @JsonCreator private constructor() : this(mutableMapOf()) - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [SessionExecuteAgentResponse]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [SessionExecuteAgentResponse]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(sessionExecuteAgentResponse: SessionExecuteAgentResponse) = apply { - additionalProperties = sessionExecuteAgentResponse.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [SessionExecuteAgentResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): SessionExecuteAgentResponse = - SessionExecuteAgentResponse(additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): SessionExecuteAgentResponse = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = 0 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is SessionExecuteAgentResponse && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "SessionExecuteAgentResponse{additionalProperties=$additionalProperties}" -} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt new file mode 100644 index 0000000..4b615cf --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -0,0 +1,1403 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.Params +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ +class SessionExecuteParams +private constructor( + private val id: String?, + private val xLanguage: XLanguage?, + private val xSdkVersion: String?, + private val xSentAt: OffsetDateTime?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) + + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun agentConfig(): AgentConfig = body.agentConfig() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun executeOptions(): ExecuteOptions = body.executeOptions() + + /** + * Target frame ID for the agent + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * Returns the raw JSON value of [agentConfig]. + * + * Unlike [agentConfig], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _agentConfig(): JsonField = body._agentConfig() + + /** + * Returns the raw JSON value of [executeOptions]. + * + * Unlike [executeOptions], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _executeOptions(): JsonField = body._executeOptions() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionExecuteParams]. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExecuteParams]. */ + class Builder internal constructor() { + + private var id: String? = null + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionExecuteParams: SessionExecuteParams) = apply { + id = sessionExecuteParams.id + xLanguage = sessionExecuteParams.xLanguage + xSdkVersion = sessionExecuteParams.xSdkVersion + xSentAt = sessionExecuteParams.xSentAt + xStreamResponse = sessionExecuteParams.xStreamResponse + body = sessionExecuteParams.body.toBuilder() + additionalHeaders = sessionExecuteParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionExecuteParams.additionalQueryParams.toBuilder() + } + + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } + + /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } + + /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } + + /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [agentConfig] + * - [executeOptions] + * - [frameId] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + fun agentConfig(agentConfig: AgentConfig) = apply { body.agentConfig(agentConfig) } + + /** + * Sets [Builder.agentConfig] to an arbitrary JSON value. + * + * You should usually call [Builder.agentConfig] with a well-typed [AgentConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun agentConfig(agentConfig: JsonField) = apply { + body.agentConfig(agentConfig) + } + + fun executeOptions(executeOptions: ExecuteOptions) = apply { + body.executeOptions(executeOptions) + } + + /** + * Sets [Builder.executeOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.executeOptions] with a well-typed [ExecuteOptions] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun executeOptions(executeOptions: JsonField) = apply { + body.executeOptions(executeOptions) + } + + /** Target frame ID for the agent */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionExecuteParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionExecuteParams = + SessionExecuteParams( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val agentConfig: JsonField, + private val executeOptions: JsonField, + private val frameId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("agentConfig") + @ExcludeMissing + agentConfig: JsonField = JsonMissing.of(), + @JsonProperty("executeOptions") + @ExcludeMissing + executeOptions: JsonField = JsonMissing.of(), + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + ) : this(agentConfig, executeOptions, frameId, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun agentConfig(): AgentConfig = agentConfig.getRequired("agentConfig") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun executeOptions(): ExecuteOptions = executeOptions.getRequired("executeOptions") + + /** + * Target frame ID for the agent + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * Returns the raw JSON value of [agentConfig]. + * + * Unlike [agentConfig], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("agentConfig") + @ExcludeMissing + fun _agentConfig(): JsonField = agentConfig + + /** + * Returns the raw JSON value of [executeOptions]. + * + * Unlike [executeOptions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("executeOptions") + @ExcludeMissing + fun _executeOptions(): JsonField = executeOptions + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var agentConfig: JsonField? = null + private var executeOptions: JsonField? = null + private var frameId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + agentConfig = body.agentConfig + executeOptions = body.executeOptions + frameId = body.frameId + additionalProperties = body.additionalProperties.toMutableMap() + } + + fun agentConfig(agentConfig: AgentConfig) = agentConfig(JsonField.of(agentConfig)) + + /** + * Sets [Builder.agentConfig] to an arbitrary JSON value. + * + * You should usually call [Builder.agentConfig] with a well-typed [AgentConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun agentConfig(agentConfig: JsonField) = apply { + this.agentConfig = agentConfig + } + + fun executeOptions(executeOptions: ExecuteOptions) = + executeOptions(JsonField.of(executeOptions)) + + /** + * Sets [Builder.executeOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.executeOptions] with a well-typed [ExecuteOptions] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun executeOptions(executeOptions: JsonField) = apply { + this.executeOptions = executeOptions + } + + /** Target frame ID for the agent */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .agentConfig() + * .executeOptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("agentConfig", agentConfig), + checkRequired("executeOptions", executeOptions), + frameId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + agentConfig().validate() + executeOptions().validate() + frameId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (agentConfig.asKnown().getOrNull()?.validity() ?: 0) + + (executeOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (frameId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + agentConfig == other.agentConfig && + executeOptions == other.executeOptions && + frameId == other.frameId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(agentConfig, executeOptions, frameId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{agentConfig=$agentConfig, executeOptions=$executeOptions, frameId=$frameId, additionalProperties=$additionalProperties}" + } + + class AgentConfig + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cua: JsonField, + private val model: JsonField, + private val systemPrompt: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("systemPrompt") + @ExcludeMissing + systemPrompt: JsonField = JsonMissing.of(), + ) : this(cua, model, systemPrompt, mutableMapOf()) + + /** + * Enable Computer Use Agent mode + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cua(): Optional = cua.getOptional("cua") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * Custom system prompt for the agent + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") + + /** + * Returns the raw JSON value of [cua]. + * + * Unlike [cua], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cua") @ExcludeMissing fun _cua(): JsonField = cua + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [systemPrompt]. + * + * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("systemPrompt") + @ExcludeMissing + fun _systemPrompt(): JsonField = systemPrompt + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [AgentConfig]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AgentConfig]. */ + class Builder internal constructor() { + + private var cua: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() + private var systemPrompt: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(agentConfig: AgentConfig) = apply { + cua = agentConfig.cua + model = agentConfig.model + systemPrompt = agentConfig.systemPrompt + additionalProperties = agentConfig.additionalProperties.toMutableMap() + } + + /** Enable Computer Use Agent mode */ + fun cua(cua: Boolean) = cua(JsonField.of(cua)) + + /** + * Sets [Builder.cua] to an arbitrary JSON value. + * + * You should usually call [Builder.cua] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun cua(cua: JsonField) = apply { this.cua = cua } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) + + /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ + fun model(unionMember1: ModelConfig.UnionMember1) = + model(ModelConfig.ofUnionMember1(unionMember1)) + + /** Custom system prompt for the agent */ + fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) + + /** + * Sets [Builder.systemPrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.systemPrompt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun systemPrompt(systemPrompt: JsonField) = apply { + this.systemPrompt = systemPrompt + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AgentConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AgentConfig = + AgentConfig(cua, model, systemPrompt, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): AgentConfig = apply { + if (validated) { + return@apply + } + + cua() + model().ifPresent { it.validate() } + systemPrompt() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (cua.asKnown().isPresent) 1 else 0) + + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (systemPrompt.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AgentConfig && + cua == other.cua && + model == other.model && + systemPrompt == other.systemPrompt && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(cua, model, systemPrompt, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AgentConfig{cua=$cua, model=$model, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" + } + + class ExecuteOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val instruction: JsonField, + private val highlightCursor: JsonField, + private val maxSteps: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("highlightCursor") + @ExcludeMissing + highlightCursor: JsonField = JsonMissing.of(), + @JsonProperty("maxSteps") @ExcludeMissing maxSteps: JsonField = JsonMissing.of(), + ) : this(instruction, highlightCursor, maxSteps, mutableMapOf()) + + /** + * Natural language instruction for the agent + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun instruction(): String = instruction.getRequired("instruction") + + /** + * Whether to visually highlight the cursor during execution + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun highlightCursor(): Optional = highlightCursor.getOptional("highlightCursor") + + /** + * Maximum number of steps the agent can take + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [highlightCursor]. + * + * Unlike [highlightCursor], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("highlightCursor") + @ExcludeMissing + fun _highlightCursor(): JsonField = highlightCursor + + /** + * Returns the raw JSON value of [maxSteps]. + * + * Unlike [maxSteps], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("maxSteps") @ExcludeMissing fun _maxSteps(): JsonField = maxSteps + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ExecuteOptions]. + * + * The following fields are required: + * ```java + * .instruction() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ExecuteOptions]. */ + class Builder internal constructor() { + + private var instruction: JsonField? = null + private var highlightCursor: JsonField = JsonMissing.of() + private var maxSteps: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(executeOptions: ExecuteOptions) = apply { + instruction = executeOptions.instruction + highlightCursor = executeOptions.highlightCursor + maxSteps = executeOptions.maxSteps + additionalProperties = executeOptions.additionalProperties.toMutableMap() + } + + /** Natural language instruction for the agent */ + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + /** Whether to visually highlight the cursor during execution */ + fun highlightCursor(highlightCursor: Boolean) = + highlightCursor(JsonField.of(highlightCursor)) + + /** + * Sets [Builder.highlightCursor] to an arbitrary JSON value. + * + * You should usually call [Builder.highlightCursor] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun highlightCursor(highlightCursor: JsonField) = apply { + this.highlightCursor = highlightCursor + } + + /** Maximum number of steps the agent can take */ + fun maxSteps(maxSteps: Double) = maxSteps(JsonField.of(maxSteps)) + + /** + * Sets [Builder.maxSteps] to an arbitrary JSON value. + * + * You should usually call [Builder.maxSteps] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun maxSteps(maxSteps: JsonField) = apply { this.maxSteps = maxSteps } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ExecuteOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .instruction() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExecuteOptions = + ExecuteOptions( + checkRequired("instruction", instruction), + highlightCursor, + maxSteps, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ExecuteOptions = apply { + if (validated) { + return@apply + } + + instruction() + highlightCursor() + maxSteps() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (instruction.asKnown().isPresent) 1 else 0) + + (if (highlightCursor.asKnown().isPresent) 1 else 0) + + (if (maxSteps.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExecuteOptions && + instruction == other.instruction && + highlightCursor == other.highlightCursor && + maxSteps == other.maxSteps && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(instruction, highlightCursor, maxSteps, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" + } + + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExecuteParams && + id == other.id && + xLanguage == other.xLanguage && + xSdkVersion == other.xSdkVersion && + xSentAt == other.xSentAt && + xStreamResponse == other.xStreamResponse && + body == other.body && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash( + id, + xLanguage, + xSdkVersion, + xSentAt, + xStreamResponse, + body, + additionalHeaders, + additionalQueryParams, + ) + + override fun toString() = + "SessionExecuteParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt new file mode 100644 index 0000000..2478f77 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt @@ -0,0 +1,1775 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class SessionExecuteResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionExecuteResponse]. + * + * The following fields are required: + * ```java + * .data() + * .success() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionExecuteResponse]. */ + class Builder internal constructor() { + + private var data: JsonField? = null + private var success: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionExecuteResponse: SessionExecuteResponse) = apply { + data = sessionExecuteResponse.data + success = sessionExecuteResponse.success + additionalProperties = sessionExecuteResponse.additionalProperties.toMutableMap() + } + + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionExecuteResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .data() + * .success() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionExecuteResponse = + SessionExecuteResponse( + checkRequired("data", data), + checkRequired("success", success), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SessionExecuteResponse = apply { + if (validated) { + return@apply + } + + data().validate() + success().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (data.asKnown().getOrNull()?.validity() ?: 0) + + (success.asKnown().getOrNull()?.validity() ?: 0) + + class Data + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val result: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("result") @ExcludeMissing result: JsonField = JsonMissing.of() + ) : this(result, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun result(): Result = result.getRequired("result") + + /** + * Returns the raw JSON value of [result]. + * + * Unlike [result], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonField = result + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .result() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var result: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + result = data.result + additionalProperties = data.additionalProperties.toMutableMap() + } + + fun result(result: Result) = result(JsonField.of(result)) + + /** + * Sets [Builder.result] to an arbitrary JSON value. + * + * You should usually call [Builder.result] with a well-typed [Result] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun result(result: JsonField) = apply { this.result = result } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .result() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Data = + Data(checkRequired("result", result), additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + result().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (result.asKnown().getOrNull()?.validity() ?: 0) + + class Result + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val actions: JsonField>, + private val completed: JsonField, + private val message: JsonField, + private val success: JsonField, + private val metadata: JsonField, + private val usage: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("actions") + @ExcludeMissing + actions: JsonField> = JsonMissing.of(), + @JsonProperty("completed") + @ExcludeMissing + completed: JsonField = JsonMissing.of(), + @JsonProperty("message") + @ExcludeMissing + message: JsonField = JsonMissing.of(), + @JsonProperty("success") + @ExcludeMissing + success: JsonField = JsonMissing.of(), + @JsonProperty("metadata") + @ExcludeMissing + metadata: JsonField = JsonMissing.of(), + @JsonProperty("usage") @ExcludeMissing usage: JsonField = JsonMissing.of(), + ) : this(actions, completed, message, success, metadata, usage, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun actions(): List = actions.getRequired("actions") + + /** + * Whether the agent finished its task + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun completed(): Boolean = completed.getRequired("completed") + + /** + * Summary of what the agent accomplished + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun message(): String = message.getRequired("message") + + /** + * Whether the agent completed successfully + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun success(): Boolean = success.getRequired("success") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun metadata(): Optional = metadata.getOptional("metadata") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun usage(): Optional = usage.getOptional("usage") + + /** + * Returns the raw JSON value of [actions]. + * + * Unlike [actions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actions") + @ExcludeMissing + fun _actions(): JsonField> = actions + + /** + * Returns the raw JSON value of [completed]. + * + * Unlike [completed], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("completed") + @ExcludeMissing + fun _completed(): JsonField = completed + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("metadata") + @ExcludeMissing + fun _metadata(): JsonField = metadata + + /** + * Returns the raw JSON value of [usage]. + * + * Unlike [usage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("usage") @ExcludeMissing fun _usage(): JsonField = usage + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Result]. + * + * The following fields are required: + * ```java + * .actions() + * .completed() + * .message() + * .success() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Result]. */ + class Builder internal constructor() { + + private var actions: JsonField>? = null + private var completed: JsonField? = null + private var message: JsonField? = null + private var success: JsonField? = null + private var metadata: JsonField = JsonMissing.of() + private var usage: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(result: Result) = apply { + actions = result.actions.map { it.toMutableList() } + completed = result.completed + message = result.message + success = result.success + metadata = result.metadata + usage = result.usage + additionalProperties = result.additionalProperties.toMutableMap() + } + + fun actions(actions: List) = actions(JsonField.of(actions)) + + /** + * Sets [Builder.actions] to an arbitrary JSON value. + * + * You should usually call [Builder.actions] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun actions(actions: JsonField>) = apply { + this.actions = actions.map { it.toMutableList() } + } + + /** + * Adds a single [Action] to [actions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAction(action: Action) = apply { + actions = + (actions ?: JsonField.of(mutableListOf())).also { + checkKnown("actions", it).add(action) + } + } + + /** Whether the agent finished its task */ + fun completed(completed: Boolean) = completed(JsonField.of(completed)) + + /** + * Sets [Builder.completed] to an arbitrary JSON value. + * + * You should usually call [Builder.completed] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun completed(completed: JsonField) = apply { this.completed = completed } + + /** Summary of what the agent accomplished */ + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** Whether the agent completed successfully */ + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + + /** + * Sets [Builder.metadata] to an arbitrary JSON value. + * + * You should usually call [Builder.metadata] with a well-typed [Metadata] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun metadata(metadata: JsonField) = apply { this.metadata = metadata } + + fun usage(usage: Usage) = usage(JsonField.of(usage)) + + /** + * Sets [Builder.usage] to an arbitrary JSON value. + * + * You should usually call [Builder.usage] with a well-typed [Usage] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun usage(usage: JsonField) = apply { this.usage = usage } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Result]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .actions() + * .completed() + * .message() + * .success() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Result = + Result( + checkRequired("actions", actions).map { it.toImmutable() }, + checkRequired("completed", completed), + checkRequired("message", message), + checkRequired("success", success), + metadata, + usage, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Result = apply { + if (validated) { + return@apply + } + + actions().forEach { it.validate() } + completed() + message() + success() + metadata().ifPresent { it.validate() } + usage().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (completed.asKnown().isPresent) 1 else 0) + + (if (message.asKnown().isPresent) 1 else 0) + + (if (success.asKnown().isPresent) 1 else 0) + + (metadata.asKnown().getOrNull()?.validity() ?: 0) + + (usage.asKnown().getOrNull()?.validity() ?: 0) + + class Action + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val type: JsonField, + private val action: JsonField, + private val instruction: JsonField, + private val pageText: JsonField, + private val pageUrl: JsonField, + private val reasoning: JsonField, + private val taskCompleted: JsonField, + private val timeMs: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("action") + @ExcludeMissing + action: JsonField = JsonMissing.of(), + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("pageText") + @ExcludeMissing + pageText: JsonField = JsonMissing.of(), + @JsonProperty("pageUrl") + @ExcludeMissing + pageUrl: JsonField = JsonMissing.of(), + @JsonProperty("reasoning") + @ExcludeMissing + reasoning: JsonField = JsonMissing.of(), + @JsonProperty("taskCompleted") + @ExcludeMissing + taskCompleted: JsonField = JsonMissing.of(), + @JsonProperty("timeMs") + @ExcludeMissing + timeMs: JsonField = JsonMissing.of(), + ) : this( + type, + action, + instruction, + pageText, + pageUrl, + reasoning, + taskCompleted, + timeMs, + mutableMapOf(), + ) + + /** + * Type of action taken + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun type(): String = type.getRequired("type") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun action(): Optional = action.getOptional("action") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun instruction(): Optional = instruction.getOptional("instruction") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun pageText(): Optional = pageText.getOptional("pageText") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun pageUrl(): Optional = pageUrl.getOptional("pageUrl") + + /** + * Agent's reasoning for taking this action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun reasoning(): Optional = reasoning.getOptional("reasoning") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun taskCompleted(): Optional = taskCompleted.getOptional("taskCompleted") + + /** + * Time taken for this action in ms + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun timeMs(): Optional = timeMs.getOptional("timeMs") + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [action]. + * + * Unlike [action], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("action") @ExcludeMissing fun _action(): JsonField = action + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [pageText]. + * + * Unlike [pageText], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pageText") + @ExcludeMissing + fun _pageText(): JsonField = pageText + + /** + * Returns the raw JSON value of [pageUrl]. + * + * Unlike [pageUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pageUrl") @ExcludeMissing fun _pageUrl(): JsonField = pageUrl + + /** + * Returns the raw JSON value of [reasoning]. + * + * Unlike [reasoning], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("reasoning") + @ExcludeMissing + fun _reasoning(): JsonField = reasoning + + /** + * Returns the raw JSON value of [taskCompleted]. + * + * Unlike [taskCompleted], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("taskCompleted") + @ExcludeMissing + fun _taskCompleted(): JsonField = taskCompleted + + /** + * Returns the raw JSON value of [timeMs]. + * + * Unlike [timeMs], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("timeMs") @ExcludeMissing fun _timeMs(): JsonField = timeMs + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Action]. + * + * The following fields are required: + * ```java + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Action]. */ + class Builder internal constructor() { + + private var type: JsonField? = null + private var action: JsonField = JsonMissing.of() + private var instruction: JsonField = JsonMissing.of() + private var pageText: JsonField = JsonMissing.of() + private var pageUrl: JsonField = JsonMissing.of() + private var reasoning: JsonField = JsonMissing.of() + private var taskCompleted: JsonField = JsonMissing.of() + private var timeMs: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(action: Action) = apply { + type = action.type + this.action = action.action + instruction = action.instruction + pageText = action.pageText + pageUrl = action.pageUrl + reasoning = action.reasoning + taskCompleted = action.taskCompleted + timeMs = action.timeMs + additionalProperties = action.additionalProperties.toMutableMap() + } + + /** Type of action taken */ + fun type(type: String) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun action(action: String) = action(JsonField.of(action)) + + /** + * Sets [Builder.action] to an arbitrary JSON value. + * + * You should usually call [Builder.action] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun action(action: JsonField) = apply { this.action = action } + + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + fun pageText(pageText: String) = pageText(JsonField.of(pageText)) + + /** + * Sets [Builder.pageText] to an arbitrary JSON value. + * + * You should usually call [Builder.pageText] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun pageText(pageText: JsonField) = apply { this.pageText = pageText } + + fun pageUrl(pageUrl: String) = pageUrl(JsonField.of(pageUrl)) + + /** + * Sets [Builder.pageUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.pageUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun pageUrl(pageUrl: JsonField) = apply { this.pageUrl = pageUrl } + + /** Agent's reasoning for taking this action */ + fun reasoning(reasoning: String) = reasoning(JsonField.of(reasoning)) + + /** + * Sets [Builder.reasoning] to an arbitrary JSON value. + * + * You should usually call [Builder.reasoning] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun reasoning(reasoning: JsonField) = apply { + this.reasoning = reasoning + } + + fun taskCompleted(taskCompleted: Boolean) = + taskCompleted(JsonField.of(taskCompleted)) + + /** + * Sets [Builder.taskCompleted] to an arbitrary JSON value. + * + * You should usually call [Builder.taskCompleted] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun taskCompleted(taskCompleted: JsonField) = apply { + this.taskCompleted = taskCompleted + } + + /** Time taken for this action in ms */ + fun timeMs(timeMs: Double) = timeMs(JsonField.of(timeMs)) + + /** + * Sets [Builder.timeMs] to an arbitrary JSON value. + * + * You should usually call [Builder.timeMs] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun timeMs(timeMs: JsonField) = apply { this.timeMs = timeMs } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Action]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Action = + Action( + checkRequired("type", type), + action, + instruction, + pageText, + pageUrl, + reasoning, + taskCompleted, + timeMs, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Action = apply { + if (validated) { + return@apply + } + + type() + action() + instruction() + pageText() + pageUrl() + reasoning() + taskCompleted() + timeMs() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (type.asKnown().isPresent) 1 else 0) + + (if (action.asKnown().isPresent) 1 else 0) + + (if (instruction.asKnown().isPresent) 1 else 0) + + (if (pageText.asKnown().isPresent) 1 else 0) + + (if (pageUrl.asKnown().isPresent) 1 else 0) + + (if (reasoning.asKnown().isPresent) 1 else 0) + + (if (taskCompleted.asKnown().isPresent) 1 else 0) + + (if (timeMs.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Action && + type == other.type && + action == other.action && + instruction == other.instruction && + pageText == other.pageText && + pageUrl == other.pageUrl && + reasoning == other.reasoning && + taskCompleted == other.taskCompleted && + timeMs == other.timeMs && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + type, + action, + instruction, + pageText, + pageUrl, + reasoning, + taskCompleted, + timeMs, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Action{type=$type, action=$action, instruction=$instruction, pageText=$pageText, pageUrl=$pageUrl, reasoning=$reasoning, taskCompleted=$taskCompleted, timeMs=$timeMs, additionalProperties=$additionalProperties}" + } + + class Metadata + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Metadata]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(metadata: Metadata) = apply { + additionalProperties = metadata.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Metadata]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Metadata = Metadata(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Metadata && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Metadata{additionalProperties=$additionalProperties}" + } + + class Usage + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val inferenceTimeMs: JsonField, + private val inputTokens: JsonField, + private val outputTokens: JsonField, + private val cachedInputTokens: JsonField, + private val reasoningTokens: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("inference_time_ms") + @ExcludeMissing + inferenceTimeMs: JsonField = JsonMissing.of(), + @JsonProperty("input_tokens") + @ExcludeMissing + inputTokens: JsonField = JsonMissing.of(), + @JsonProperty("output_tokens") + @ExcludeMissing + outputTokens: JsonField = JsonMissing.of(), + @JsonProperty("cached_input_tokens") + @ExcludeMissing + cachedInputTokens: JsonField = JsonMissing.of(), + @JsonProperty("reasoning_tokens") + @ExcludeMissing + reasoningTokens: JsonField = JsonMissing.of(), + ) : this( + inferenceTimeMs, + inputTokens, + outputTokens, + cachedInputTokens, + reasoningTokens, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun inferenceTimeMs(): Double = inferenceTimeMs.getRequired("inference_time_ms") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun inputTokens(): Double = inputTokens.getRequired("input_tokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun outputTokens(): Double = outputTokens.getRequired("output_tokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun cachedInputTokens(): Optional = + cachedInputTokens.getOptional("cached_input_tokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun reasoningTokens(): Optional = + reasoningTokens.getOptional("reasoning_tokens") + + /** + * Returns the raw JSON value of [inferenceTimeMs]. + * + * Unlike [inferenceTimeMs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("inference_time_ms") + @ExcludeMissing + fun _inferenceTimeMs(): JsonField = inferenceTimeMs + + /** + * Returns the raw JSON value of [inputTokens]. + * + * Unlike [inputTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("input_tokens") + @ExcludeMissing + fun _inputTokens(): JsonField = inputTokens + + /** + * Returns the raw JSON value of [outputTokens]. + * + * Unlike [outputTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("output_tokens") + @ExcludeMissing + fun _outputTokens(): JsonField = outputTokens + + /** + * Returns the raw JSON value of [cachedInputTokens]. + * + * Unlike [cachedInputTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("cached_input_tokens") + @ExcludeMissing + fun _cachedInputTokens(): JsonField = cachedInputTokens + + /** + * Returns the raw JSON value of [reasoningTokens]. + * + * Unlike [reasoningTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("reasoning_tokens") + @ExcludeMissing + fun _reasoningTokens(): JsonField = reasoningTokens + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Usage]. + * + * The following fields are required: + * ```java + * .inferenceTimeMs() + * .inputTokens() + * .outputTokens() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Usage]. */ + class Builder internal constructor() { + + private var inferenceTimeMs: JsonField? = null + private var inputTokens: JsonField? = null + private var outputTokens: JsonField? = null + private var cachedInputTokens: JsonField = JsonMissing.of() + private var reasoningTokens: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(usage: Usage) = apply { + inferenceTimeMs = usage.inferenceTimeMs + inputTokens = usage.inputTokens + outputTokens = usage.outputTokens + cachedInputTokens = usage.cachedInputTokens + reasoningTokens = usage.reasoningTokens + additionalProperties = usage.additionalProperties.toMutableMap() + } + + fun inferenceTimeMs(inferenceTimeMs: Double) = + inferenceTimeMs(JsonField.of(inferenceTimeMs)) + + /** + * Sets [Builder.inferenceTimeMs] to an arbitrary JSON value. + * + * You should usually call [Builder.inferenceTimeMs] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun inferenceTimeMs(inferenceTimeMs: JsonField) = apply { + this.inferenceTimeMs = inferenceTimeMs + } + + fun inputTokens(inputTokens: Double) = inputTokens(JsonField.of(inputTokens)) + + /** + * Sets [Builder.inputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.inputTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun inputTokens(inputTokens: JsonField) = apply { + this.inputTokens = inputTokens + } + + fun outputTokens(outputTokens: Double) = + outputTokens(JsonField.of(outputTokens)) + + /** + * Sets [Builder.outputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.outputTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun outputTokens(outputTokens: JsonField) = apply { + this.outputTokens = outputTokens + } + + fun cachedInputTokens(cachedInputTokens: Double) = + cachedInputTokens(JsonField.of(cachedInputTokens)) + + /** + * Sets [Builder.cachedInputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.cachedInputTokens] with a well-typed + * [Double] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun cachedInputTokens(cachedInputTokens: JsonField) = apply { + this.cachedInputTokens = cachedInputTokens + } + + fun reasoningTokens(reasoningTokens: Double) = + reasoningTokens(JsonField.of(reasoningTokens)) + + /** + * Sets [Builder.reasoningTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.reasoningTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun reasoningTokens(reasoningTokens: JsonField) = apply { + this.reasoningTokens = reasoningTokens + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Usage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .inferenceTimeMs() + * .inputTokens() + * .outputTokens() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Usage = + Usage( + checkRequired("inferenceTimeMs", inferenceTimeMs), + checkRequired("inputTokens", inputTokens), + checkRequired("outputTokens", outputTokens), + cachedInputTokens, + reasoningTokens, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Usage = apply { + if (validated) { + return@apply + } + + inferenceTimeMs() + inputTokens() + outputTokens() + cachedInputTokens() + reasoningTokens() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (inferenceTimeMs.asKnown().isPresent) 1 else 0) + + (if (inputTokens.asKnown().isPresent) 1 else 0) + + (if (outputTokens.asKnown().isPresent) 1 else 0) + + (if (cachedInputTokens.asKnown().isPresent) 1 else 0) + + (if (reasoningTokens.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Usage && + inferenceTimeMs == other.inferenceTimeMs && + inputTokens == other.inputTokens && + outputTokens == other.outputTokens && + cachedInputTokens == other.cachedInputTokens && + reasoningTokens == other.reasoningTokens && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + inferenceTimeMs, + inputTokens, + outputTokens, + cachedInputTokens, + reasoningTokens, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Usage{inferenceTimeMs=$inferenceTimeMs, inputTokens=$inputTokens, outputTokens=$outputTokens, cachedInputTokens=$cachedInputTokens, reasoningTokens=$reasoningTokens, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Result && + actions == other.actions && + completed == other.completed && + message == other.message && + success == other.success && + metadata == other.metadata && + usage == other.usage && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + actions, + completed, + message, + success, + metadata, + usage, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Result{actions=$actions, completed=$completed, message=$message, success=$success, metadata=$metadata, usage=$usage, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + result == other.result && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(result, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Data{result=$result, additionalProperties=$additionalProperties}" + } + + class Success @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionExecuteResponse && + data == other.data && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(data, success, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionExecuteResponse{data=$data, success=$success, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 18414ff..b86cdc3 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -2,11 +2,23 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,27 +26,90 @@ import kotlin.jvm.optionals.getOrNull /** Extracts structured data from the current page using AI-powered analysis. */ class SessionExtractParams private constructor( - private val id: JsonValue?, - private val xLanguage: JsonValue?, - private val xSdkVersion: JsonValue?, - private val xSentAt: JsonValue?, - private val xStreamResponse: JsonValue?, - private val body: JsonValue, + private val id: String?, + private val xLanguage: XLanguage?, + private val xSdkVersion: String?, + private val xSentAt: OffsetDateTime?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun id(): Optional = Optional.ofNullable(id) + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun body(): JsonValue = body + /** + * Target frame ID for the extraction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * Natural language instruction for what to extract + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun instruction(): Optional = body.instruction() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * JSON Schema defining the structure of data to extract + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun schema(): Optional = body.schema() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _instruction(): JsonField = body._instruction() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + /** + * Returns the raw JSON value of [schema]. + * + * Unlike [schema], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _schema(): JsonField = body._schema() + + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -55,12 +130,12 @@ private constructor( /** A builder for [SessionExtractParams]. */ class Builder internal constructor() { - private var id: JsonValue? = null - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null - private var body: JsonValue = JsonMissing.of() + private var id: String? = null + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -71,40 +146,118 @@ private constructor( xSdkVersion = sessionExtractParams.xSdkVersion xSentAt = sessionExtractParams.xSentAt xStreamResponse = sessionExtractParams.xStreamResponse - body = sessionExtractParams.body + body = sessionExtractParams.body.toBuilder() additionalHeaders = sessionExtractParams.additionalHeaders.toBuilder() additionalQueryParams = sessionExtractParams.additionalQueryParams.toBuilder() } - fun id(id: JsonValue?) = apply { this.id = id } + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } /** Alias for calling [Builder.id] with `id.orElse(null)`. */ - fun id(id: Optional) = id(id.getOrNull()) + fun id(id: Optional) = id(id.getOrNull()) - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse } /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = + fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - fun body(body: JsonValue) = apply { this.body = body } + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [frameId] + * - [instruction] + * - [options] + * - [schema] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Target frame ID for the extraction */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + /** Natural language instruction for what to extract */ + fun instruction(instruction: String) = apply { body.instruction(instruction) } + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun instruction(instruction: JsonField) = apply { body.instruction(instruction) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + /** JSON Schema defining the structure of data to extract */ + fun schema(schema: Schema) = apply { body.schema(schema) } + + /** + * Sets [Builder.schema] to an arbitrary JSON value. + * + * You should usually call [Builder.schema] with a well-typed [Schema] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun schema(schema: JsonField) = apply { body.schema(schema) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -216,24 +369,872 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, - body, + body.build(), additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): JsonValue = body + fun _body(): Body = body fun _pathParam(index: Int): String = when (index) { - 0 -> id?.toString() ?: "" + 0 -> id ?: "" else -> "" } - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val frameId: JsonField, + private val instruction: JsonField, + private val options: JsonField, + private val schema: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + @JsonProperty("schema") @ExcludeMissing schema: JsonField = JsonMissing.of(), + ) : this(frameId, instruction, options, schema, mutableMapOf()) + + /** + * Target frame ID for the extraction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * Natural language instruction for what to extract + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun instruction(): Optional = instruction.getOptional("instruction") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * JSON Schema defining the structure of data to extract + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun schema(): Optional = schema.getOptional("schema") + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + /** + * Returns the raw JSON value of [schema]. + * + * Unlike [schema], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("schema") @ExcludeMissing fun _schema(): JsonField = schema + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var frameId: JsonField = JsonMissing.of() + private var instruction: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var schema: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + frameId = body.frameId + instruction = body.instruction + options = body.options + schema = body.schema + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Target frame ID for the extraction */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + /** Natural language instruction for what to extract */ + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + /** JSON Schema defining the structure of data to extract */ + fun schema(schema: Schema) = schema(JsonField.of(schema)) + + /** + * Sets [Builder.schema] to an arbitrary JSON value. + * + * You should usually call [Builder.schema] with a well-typed [Schema] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun schema(schema: JsonField) = apply { this.schema = schema } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body(frameId, instruction, options, schema, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + frameId() + instruction() + options().ifPresent { it.validate() } + schema().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (frameId.asKnown().isPresent) 1 else 0) + + (if (instruction.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + (schema.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + frameId == other.frameId && + instruction == other.instruction && + options == other.options && + schema == other.schema && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(frameId, instruction, options, schema, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{frameId=$frameId, instruction=$instruction, options=$options, schema=$schema, additionalProperties=$additionalProperties}" + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val selector: JsonField, + private val timeout: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + ) : this(model, selector, timeout, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * CSS selector to scope extraction to a specific element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun selector(): Optional = selector.getOptional("selector") + + /** + * Timeout in ms for the extraction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var selector: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + model = options.model + selector = options.selector + timeout = options.timeout + additionalProperties = options.additionalProperties.toMutableMap() + } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) + + /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ + fun model(unionMember1: ModelConfig.UnionMember1) = + model(ModelConfig.ofUnionMember1(unionMember1)) + + /** CSS selector to scope extraction to a specific element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** Timeout in ms for the extraction */ + fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(model, selector, timeout, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + model().ifPresent { it.validate() } + selector() + timeout() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + model == other.model && + selector == other.selector && + timeout == other.timeout && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, selector, timeout, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" + } + + /** JSON Schema defining the structure of data to extract */ + class Schema + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Schema]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Schema]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(schema: Schema) = apply { + additionalProperties = schema.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Schema]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Schema = Schema(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Schema = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Schema && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Schema{additionalProperties=$additionalProperties}" + } + + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index 1e08b0f..f48f24f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -2,20 +2,61 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull class SessionExtractResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -31,20 +72,52 @@ private constructor(private val additionalProperties: MutableMap? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionExtractResponse: SessionExtractResponse) = apply { + data = sessionExtractResponse.data + success = sessionExtractResponse.success additionalProperties = sessionExtractResponse.additionalProperties.toMutableMap() } + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -68,9 +141,21 @@ private constructor(private val additionalProperties: MutableMap, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("result") @ExcludeMissing result: JsonValue = JsonMissing.of(), + @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), + ) : this(result, actionId, mutableMapOf()) + + /** Extracted data matching the requested schema */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonValue = result + + /** + * Action ID for tracking + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun actionId(): Optional = actionId.getOptional("actionId") + + /** + * Returns the raw JSON value of [actionId]. + * + * Unlike [actionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actionId") @ExcludeMissing fun _actionId(): JsonField = actionId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .result() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var result: JsonValue? = null + private var actionId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + result = data.result + actionId = data.actionId + additionalProperties = data.additionalProperties.toMutableMap() + } + + /** Extracted data matching the requested schema */ + fun result(result: JsonValue) = apply { this.result = result } + + /** Action ID for tracking */ + fun actionId(actionId: String) = actionId(JsonField.of(actionId)) + + /** + * Sets [Builder.actionId] to an arbitrary JSON value. + * + * You should usually call [Builder.actionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actionId(actionId: JsonField) = apply { this.actionId = actionId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .result() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Data = + Data(checkRequired("result", result), actionId, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + actionId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (if (actionId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + result == other.result && + actionId == other.actionId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(result, actionId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" + } + + class Success @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is SessionExtractResponse && additionalProperties == other.additionalProperties + return other is SessionExtractResponse && + data == other.data && + success == other.success && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(data, success, additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "SessionExtractResponse{additionalProperties=$additionalProperties}" + override fun toString() = + "SessionExtractResponse{data=$data, success=$success, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index 9f282ab..b07cf2c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -2,11 +2,23 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,27 +26,75 @@ import kotlin.jvm.optionals.getOrNull /** Navigates the browser to the specified URL. */ class SessionNavigateParams private constructor( - private val id: JsonValue?, - private val xLanguage: JsonValue?, - private val xSdkVersion: JsonValue?, - private val xSentAt: JsonValue?, - private val xStreamResponse: JsonValue?, - private val body: JsonValue, + private val id: String?, + private val xLanguage: XLanguage?, + private val xSdkVersion: String?, + private val xSentAt: OffsetDateTime?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun id(): Optional = Optional.ofNullable(id) + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun body(): JsonValue = body + /** + * URL to navigate to + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun url(): String = body.url() + + /** + * Target frame ID for the navigation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _url(): JsonField = body._url() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -46,21 +106,26 @@ private constructor( companion object { - @JvmStatic fun none(): SessionNavigateParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionNavigateParams]. */ + /** + * Returns a mutable builder for constructing an instance of [SessionNavigateParams]. + * + * The following fields are required: + * ```java + * .url() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionNavigateParams]. */ class Builder internal constructor() { - private var id: JsonValue? = null - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null - private var body: JsonValue = JsonMissing.of() + private var id: String? = null + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -71,40 +136,105 @@ private constructor( xSdkVersion = sessionNavigateParams.xSdkVersion xSentAt = sessionNavigateParams.xSentAt xStreamResponse = sessionNavigateParams.xStreamResponse - body = sessionNavigateParams.body + body = sessionNavigateParams.body.toBuilder() additionalHeaders = sessionNavigateParams.additionalHeaders.toBuilder() additionalQueryParams = sessionNavigateParams.additionalQueryParams.toBuilder() } - fun id(id: JsonValue?) = apply { this.id = id } + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } /** Alias for calling [Builder.id] with `id.orElse(null)`. */ - fun id(id: Optional) = id(id.getOrNull()) + fun id(id: Optional) = id(id.getOrNull()) - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse } /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = + fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - fun body(body: JsonValue) = apply { this.body = body } + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [url] + * - [frameId] + * - [options] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** URL to navigate to */ + fun url(url: String) = apply { body.url(url) } + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun url(url: JsonField) = apply { body.url(url) } + + /** Target frame ID for the navigation */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -208,6 +338,13 @@ private constructor( * Returns an immutable instance of [SessionNavigateParams]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): SessionNavigateParams = SessionNavigateParams( @@ -216,24 +353,887 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, - body, + body.build(), additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): JsonValue = body + fun _body(): Body = body fun _pathParam(index: Int): String = when (index) { - 0 -> id?.toString() ?: "" + 0 -> id ?: "" else -> "" } - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val url: JsonField, + private val frameId: JsonField, + private val options: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + ) : this(url, frameId, options, mutableMapOf()) + + /** + * URL to navigate to + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun url(): String = url.getRequired("url") + + /** + * Target frame ID for the navigation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .url() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var url: JsonField? = null + private var frameId: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + url = body.url + frameId = body.frameId + options = body.options + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** URL to navigate to */ + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + /** Target frame ID for the navigation */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("url", url), + frameId, + options, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + url() + frameId() + options().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (url.asKnown().isPresent) 1 else 0) + + (if (frameId.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + url == other.url && + frameId == other.frameId && + options == other.options && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(url, frameId, options, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{url=$url, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val referer: JsonField, + private val timeout: JsonField, + private val waitUntil: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("referer") @ExcludeMissing referer: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + @JsonProperty("waitUntil") + @ExcludeMissing + waitUntil: JsonField = JsonMissing.of(), + ) : this(referer, timeout, waitUntil, mutableMapOf()) + + /** + * Referer header to send with the request + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun referer(): Optional = referer.getOptional("referer") + + /** + * Timeout in ms for the navigation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * When to consider navigation complete + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun waitUntil(): Optional = waitUntil.getOptional("waitUntil") + + /** + * Returns the raw JSON value of [referer]. + * + * Unlike [referer], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("referer") @ExcludeMissing fun _referer(): JsonField = referer + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + /** + * Returns the raw JSON value of [waitUntil]. + * + * Unlike [waitUntil], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("waitUntil") + @ExcludeMissing + fun _waitUntil(): JsonField = waitUntil + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var referer: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var waitUntil: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + referer = options.referer + timeout = options.timeout + waitUntil = options.waitUntil + additionalProperties = options.additionalProperties.toMutableMap() + } + + /** Referer header to send with the request */ + fun referer(referer: String) = referer(JsonField.of(referer)) + + /** + * Sets [Builder.referer] to an arbitrary JSON value. + * + * You should usually call [Builder.referer] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun referer(referer: JsonField) = apply { this.referer = referer } + + /** Timeout in ms for the navigation */ + fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + /** When to consider navigation complete */ + fun waitUntil(waitUntil: WaitUntil) = waitUntil(JsonField.of(waitUntil)) + + /** + * Sets [Builder.waitUntil] to an arbitrary JSON value. + * + * You should usually call [Builder.waitUntil] with a well-typed [WaitUntil] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun waitUntil(waitUntil: JsonField) = apply { this.waitUntil = waitUntil } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(referer, timeout, waitUntil, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + referer() + timeout() + waitUntil().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (referer.asKnown().isPresent) 1 else 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + (waitUntil.asKnown().getOrNull()?.validity() ?: 0) + + /** When to consider navigation complete */ + class WaitUntil @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val LOAD = of("load") + + @JvmField val DOMCONTENTLOADED = of("domcontentloaded") + + @JvmField val NETWORKIDLE = of("networkidle") + + @JvmStatic fun of(value: String) = WaitUntil(JsonField.of(value)) + } + + /** An enum containing [WaitUntil]'s known values. */ + enum class Known { + LOAD, + DOMCONTENTLOADED, + NETWORKIDLE, + } + + /** + * An enum containing [WaitUntil]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [WaitUntil] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + LOAD, + DOMCONTENTLOADED, + NETWORKIDLE, + /** + * An enum member indicating that [WaitUntil] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + LOAD -> Value.LOAD + DOMCONTENTLOADED -> Value.DOMCONTENTLOADED + NETWORKIDLE -> Value.NETWORKIDLE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + LOAD -> Known.LOAD + DOMCONTENTLOADED -> Known.DOMCONTENTLOADED + NETWORKIDLE -> Known.NETWORKIDLE + else -> throw StagehandInvalidDataException("Unknown WaitUntil: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): WaitUntil = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is WaitUntil && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + referer == other.referer && + timeout == other.timeout && + waitUntil == other.waitUntil && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(referer, timeout, waitUntil, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{referer=$referer, timeout=$timeout, waitUntil=$waitUntil, additionalProperties=$additionalProperties}" + } + + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt index 916d1a2..56a53a4 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -2,20 +2,61 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull class SessionNavigateResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -31,20 +72,52 @@ private constructor(private val additionalProperties: MutableMap? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionNavigateResponse: SessionNavigateResponse) = apply { + data = sessionNavigateResponse.data + success = sessionNavigateResponse.success additionalProperties = sessionNavigateResponse.additionalProperties.toMutableMap() } + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -68,9 +141,21 @@ private constructor(private val additionalProperties: MutableMap, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("result") @ExcludeMissing result: JsonValue = JsonMissing.of(), + @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), + ) : this(result, actionId, mutableMapOf()) + + /** Navigation response (Playwright Response object or null) */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonValue = result + + /** + * Action ID for tracking + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun actionId(): Optional = actionId.getOptional("actionId") + + /** + * Returns the raw JSON value of [actionId]. + * + * Unlike [actionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actionId") @ExcludeMissing fun _actionId(): JsonField = actionId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .result() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var result: JsonValue? = null + private var actionId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + result = data.result + actionId = data.actionId + additionalProperties = data.additionalProperties.toMutableMap() + } + + /** Navigation response (Playwright Response object or null) */ + fun result(result: JsonValue) = apply { this.result = result } + + /** Action ID for tracking */ + fun actionId(actionId: String) = actionId(JsonField.of(actionId)) + + /** + * Sets [Builder.actionId] to an arbitrary JSON value. + * + * You should usually call [Builder.actionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actionId(actionId: JsonField) = apply { this.actionId = actionId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .result() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Data = + Data(checkRequired("result", result), actionId, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + actionId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (if (actionId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + result == other.result && + actionId == other.actionId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(result, actionId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" + } + + class Success @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { @@ -104,12 +479,15 @@ private constructor(private val additionalProperties: MutableMap = Optional.ofNullable(id) + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun body(): JsonValue = body + /** + * Target frame ID for the observation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun frameId(): Optional = body.frameId() + + /** + * Natural language instruction for what actions to find + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun instruction(): Optional = body.instruction() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun options(): Optional = body.options() + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _frameId(): JsonField = body._frameId() + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _instruction(): JsonField = body._instruction() + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _options(): JsonField = body._options() + + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -57,12 +116,12 @@ private constructor( /** A builder for [SessionObserveParams]. */ class Builder internal constructor() { - private var id: JsonValue? = null - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null - private var body: JsonValue = JsonMissing.of() + private var id: String? = null + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -73,40 +132,106 @@ private constructor( xSdkVersion = sessionObserveParams.xSdkVersion xSentAt = sessionObserveParams.xSentAt xStreamResponse = sessionObserveParams.xStreamResponse - body = sessionObserveParams.body + body = sessionObserveParams.body.toBuilder() additionalHeaders = sessionObserveParams.additionalHeaders.toBuilder() additionalQueryParams = sessionObserveParams.additionalQueryParams.toBuilder() } - fun id(id: JsonValue?) = apply { this.id = id } + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } /** Alias for calling [Builder.id] with `id.orElse(null)`. */ - fun id(id: Optional) = id(id.getOrNull()) + fun id(id: Optional) = id(id.getOrNull()) - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse } /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = + fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - fun body(body: JsonValue) = apply { this.body = body } + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [frameId] + * - [instruction] + * - [options] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Target frame ID for the observation */ + fun frameId(frameId: String) = apply { body.frameId(frameId) } + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + + /** Natural language instruction for what actions to find */ + fun instruction(instruction: String) = apply { body.instruction(instruction) } + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun instruction(instruction: JsonField) = apply { body.instruction(instruction) } + + fun options(options: Options) = apply { body.options(options) } + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun options(options: JsonField) = apply { body.options(options) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -218,24 +343,738 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, - body, + body.build(), additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): JsonValue = body + fun _body(): Body = body fun _pathParam(index: Int): String = when (index) { - 0 -> id?.toString() ?: "" + 0 -> id ?: "" else -> "" } - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val frameId: JsonField, + private val instruction: JsonField, + private val options: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), + @JsonProperty("instruction") + @ExcludeMissing + instruction: JsonField = JsonMissing.of(), + @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), + ) : this(frameId, instruction, options, mutableMapOf()) + + /** + * Target frame ID for the observation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun frameId(): Optional = frameId.getOptional("frameId") + + /** + * Natural language instruction for what actions to find + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun instruction(): Optional = instruction.getOptional("instruction") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun options(): Optional = options.getOptional("options") + + /** + * Returns the raw JSON value of [frameId]. + * + * Unlike [frameId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + + /** + * Returns the raw JSON value of [instruction]. + * + * Unlike [instruction], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("instruction") + @ExcludeMissing + fun _instruction(): JsonField = instruction + + /** + * Returns the raw JSON value of [options]. + * + * Unlike [options], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var frameId: JsonField = JsonMissing.of() + private var instruction: JsonField = JsonMissing.of() + private var options: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + frameId = body.frameId + instruction = body.instruction + options = body.options + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Target frame ID for the observation */ + fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + + /** + * Sets [Builder.frameId] to an arbitrary JSON value. + * + * You should usually call [Builder.frameId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + + /** Natural language instruction for what actions to find */ + fun instruction(instruction: String) = instruction(JsonField.of(instruction)) + + /** + * Sets [Builder.instruction] to an arbitrary JSON value. + * + * You should usually call [Builder.instruction] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun instruction(instruction: JsonField) = apply { + this.instruction = instruction + } + + fun options(options: Options) = options(JsonField.of(options)) + + /** + * Sets [Builder.options] to an arbitrary JSON value. + * + * You should usually call [Builder.options] with a well-typed [Options] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun options(options: JsonField) = apply { this.options = options } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = + Body(frameId, instruction, options, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + frameId() + instruction() + options().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (frameId.asKnown().isPresent) 1 else 0) + + (if (instruction.asKnown().isPresent) 1 else 0) + + (options.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + frameId == other.frameId && + instruction == other.instruction && + options == other.options && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(frameId, instruction, options, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{frameId=$frameId, instruction=$instruction, options=$options, additionalProperties=$additionalProperties}" + } + + class Options + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val model: JsonField, + private val selector: JsonField, + private val timeout: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + ) : this(model, selector, timeout, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun model(): Optional = model.getOptional("model") + + /** + * CSS selector to scope observation to a specific element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun selector(): Optional = selector.getOptional("selector") + + /** + * Timeout in ms for the observation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Options]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Options]. */ + class Builder internal constructor() { + + private var model: JsonField = JsonMissing.of() + private var selector: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(options: Options) = apply { + model = options.model + selector = options.selector + timeout = options.timeout + additionalProperties = options.additionalProperties.toMutableMap() + } + + fun model(model: ModelConfig) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [ModelConfig] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) + + /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ + fun model(unionMember1: ModelConfig.UnionMember1) = + model(ModelConfig.ofUnionMember1(unionMember1)) + + /** CSS selector to scope observation to a specific element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** Timeout in ms for the observation */ + fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Options]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Options = + Options(model, selector, timeout, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Options = apply { + if (validated) { + return@apply + } + + model().ifPresent { it.validate() } + selector() + timeout() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (model.asKnown().getOrNull()?.validity() ?: 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Options && + model == other.model && + selector == other.selector && + timeout == other.timeout && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(model, selector, timeout, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" + } + + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt index a27fc10..a06fd48 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt @@ -2,20 +2,63 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull class SessionObserveResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -31,20 +74,52 @@ private constructor(private val additionalProperties: MutableMap? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionObserveResponse: SessionObserveResponse) = apply { + data = sessionObserveResponse.data + success = sessionObserveResponse.success additionalProperties = sessionObserveResponse.additionalProperties.toMutableMap() } + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -68,9 +143,21 @@ private constructor(private val additionalProperties: MutableMap>, + private val actionId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("result") + @ExcludeMissing + result: JsonField> = JsonMissing.of(), + @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), + ) : this(result, actionId, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun result(): List = result.getRequired("result") + + /** + * Action ID for tracking + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun actionId(): Optional = actionId.getOptional("actionId") + + /** + * Returns the raw JSON value of [result]. + * + * Unlike [result], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonField> = result + + /** + * Returns the raw JSON value of [actionId]. + * + * Unlike [actionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actionId") @ExcludeMissing fun _actionId(): JsonField = actionId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .result() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var result: JsonField>? = null + private var actionId: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + result = data.result.map { it.toMutableList() } + actionId = data.actionId + additionalProperties = data.additionalProperties.toMutableMap() + } + + fun result(result: List) = result(JsonField.of(result)) + + /** + * Sets [Builder.result] to an arbitrary JSON value. + * + * You should usually call [Builder.result] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun result(result: JsonField>) = apply { + this.result = result.map { it.toMutableList() } + } + + /** + * Adds a single [Action] to [Builder.result]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addResult(result: Action) = apply { + this.result = + (this.result ?: JsonField.of(mutableListOf())).also { + checkKnown("result", it).add(result) + } + } + + /** Action ID for tracking */ + fun actionId(actionId: String) = actionId(JsonField.of(actionId)) + + /** + * Sets [Builder.actionId] to an arbitrary JSON value. + * + * You should usually call [Builder.actionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actionId(actionId: JsonField) = apply { this.actionId = actionId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .result() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Data = + Data( + checkRequired("result", result).map { it.toImmutable() }, + actionId, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + result().forEach { it.validate() } + actionId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (result.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (actionId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + result == other.result && + actionId == other.actionId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(result, actionId, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" + } + + class Success @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is SessionObserveResponse && additionalProperties == other.additionalProperties + return other is SessionObserveResponse && + data == other.data && + success == other.success && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(data, success, additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "SessionObserveResponse{additionalProperties=$additionalProperties}" + override fun toString() = + "SessionObserveResponse{data=$data, success=$success, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index e0c55aa..20ba71d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -2,11 +2,36 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter +import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -17,24 +42,204 @@ import kotlin.jvm.optionals.getOrNull */ class SessionStartParams private constructor( - private val xLanguage: JsonValue?, - private val xSdkVersion: JsonValue?, - private val xSentAt: JsonValue?, - private val xStreamResponse: JsonValue?, - private val body: JsonValue, + private val xLanguage: XLanguage?, + private val xSdkVersion: String?, + private val xSentAt: OffsetDateTime?, + private val xStreamResponse: XStreamResponse?, + private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) + /** Client SDK language */ + fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) + /** Version of the Stagehand SDK */ + fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) + /** ISO timestamp when request was sent */ + fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun body(): JsonValue = body + /** + * Model name to use for AI operations + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun modelName(): String = body.modelName() + + /** + * Timeout in ms for act operations + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun actTimeoutMs(): Optional = body.actTimeoutMs() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun browser(): Optional = body.browser() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun browserbaseSessionCreateParams(): Optional = + body.browserbaseSessionCreateParams() + + /** + * Existing Browserbase session ID to resume + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun browserbaseSessionId(): Optional = body.browserbaseSessionId() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun debugDom(): Optional = body.debugDom() + + /** + * Timeout in ms to wait for DOM to settle + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun domSettleTimeoutMs(): Optional = body.domSettleTimeoutMs() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun experimental(): Optional = body.experimental() + + /** + * Enable self-healing for failed actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun selfHeal(): Optional = body.selfHeal() + + /** + * Custom system prompt for AI operations + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun systemPrompt(): Optional = body.systemPrompt() + + /** + * Logging verbosity level (0=quiet, 1=normal, 2=debug) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun verbose(): Optional = body.verbose() + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun waitForCaptchaSolves(): Optional = body.waitForCaptchaSolves() + + /** + * Returns the raw JSON value of [modelName]. + * + * Unlike [modelName], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _modelName(): JsonField = body._modelName() + + /** + * Returns the raw JSON value of [actTimeoutMs]. + * + * Unlike [actTimeoutMs], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _actTimeoutMs(): JsonField = body._actTimeoutMs() + + /** + * Returns the raw JSON value of [browser]. + * + * Unlike [browser], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _browser(): JsonField = body._browser() + + /** + * Returns the raw JSON value of [browserbaseSessionCreateParams]. + * + * Unlike [browserbaseSessionCreateParams], this method doesn't throw if the JSON field has an + * unexpected type. + */ + fun _browserbaseSessionCreateParams(): JsonField = + body._browserbaseSessionCreateParams() + + /** + * Returns the raw JSON value of [browserbaseSessionId]. + * + * Unlike [browserbaseSessionId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _browserbaseSessionId(): JsonField = body._browserbaseSessionId() + + /** + * Returns the raw JSON value of [debugDom]. + * + * Unlike [debugDom], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _debugDom(): JsonField = body._debugDom() + + /** + * Returns the raw JSON value of [domSettleTimeoutMs]. + * + * Unlike [domSettleTimeoutMs], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _domSettleTimeoutMs(): JsonField = body._domSettleTimeoutMs() + + /** + * Returns the raw JSON value of [experimental]. + * + * Unlike [experimental], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _experimental(): JsonField = body._experimental() + + /** + * Returns the raw JSON value of [selfHeal]. + * + * Unlike [selfHeal], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _selfHeal(): JsonField = body._selfHeal() + + /** + * Returns the raw JSON value of [systemPrompt]. + * + * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _systemPrompt(): JsonField = body._systemPrompt() + + /** + * Returns the raw JSON value of [verbose]. + * + * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _verbose(): JsonField = body._verbose() + + /** + * Returns the raw JSON value of [waitForCaptchaSolves]. + * + * Unlike [waitForCaptchaSolves], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _waitForCaptchaSolves(): JsonField = body._waitForCaptchaSolves() + + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -46,20 +251,25 @@ private constructor( companion object { - @JvmStatic fun none(): SessionStartParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionStartParams]. */ + /** + * Returns a mutable builder for constructing an instance of [SessionStartParams]. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionStartParams]. */ class Builder internal constructor() { - private var xLanguage: JsonValue? = null - private var xSdkVersion: JsonValue? = null - private var xSentAt: JsonValue? = null - private var xStreamResponse: JsonValue? = null - private var body: JsonValue = JsonMissing.of() + private var xLanguage: XLanguage? = null + private var xSdkVersion: String? = null + private var xSentAt: OffsetDateTime? = null + private var xStreamResponse: XStreamResponse? = null + private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -69,35 +279,229 @@ private constructor( xSdkVersion = sessionStartParams.xSdkVersion xSentAt = sessionStartParams.xSentAt xStreamResponse = sessionStartParams.xStreamResponse - body = sessionStartParams.body + body = sessionStartParams.body.toBuilder() additionalHeaders = sessionStartParams.additionalHeaders.toBuilder() additionalQueryParams = sessionStartParams.additionalQueryParams.toBuilder() } - fun xLanguage(xLanguage: JsonValue?) = apply { this.xLanguage = xLanguage } + /** Client SDK language */ + fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) + fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - fun xSdkVersion(xSdkVersion: JsonValue?) = apply { this.xSdkVersion = xSdkVersion } + /** Version of the Stagehand SDK */ + fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) + fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - fun xSentAt(xSentAt: JsonValue?) = apply { this.xSentAt = xSentAt } + /** ISO timestamp when request was sent */ + fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) + fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - fun xStreamResponse(xStreamResponse: JsonValue?) = apply { + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse } /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ - fun xStreamResponse(xStreamResponse: Optional) = + fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - fun body(body: JsonValue) = apply { this.body = body } + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [modelName] + * - [actTimeoutMs] + * - [browser] + * - [browserbaseSessionCreateParams] + * - [browserbaseSessionId] + * - etc. + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** Model name to use for AI operations */ + fun modelName(modelName: String) = apply { body.modelName(modelName) } + + /** + * Sets [Builder.modelName] to an arbitrary JSON value. + * + * You should usually call [Builder.modelName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun modelName(modelName: JsonField) = apply { body.modelName(modelName) } + + /** Timeout in ms for act operations */ + fun actTimeoutMs(actTimeoutMs: Double) = apply { body.actTimeoutMs(actTimeoutMs) } + + /** + * Sets [Builder.actTimeoutMs] to an arbitrary JSON value. + * + * You should usually call [Builder.actTimeoutMs] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun actTimeoutMs(actTimeoutMs: JsonField) = apply { + body.actTimeoutMs(actTimeoutMs) + } + + fun browser(browser: Browser) = apply { body.browser(browser) } + + /** + * Sets [Builder.browser] to an arbitrary JSON value. + * + * You should usually call [Builder.browser] with a well-typed [Browser] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun browser(browser: JsonField) = apply { body.browser(browser) } + + fun browserbaseSessionCreateParams( + browserbaseSessionCreateParams: BrowserbaseSessionCreateParams + ) = apply { body.browserbaseSessionCreateParams(browserbaseSessionCreateParams) } + + /** + * Sets [Builder.browserbaseSessionCreateParams] to an arbitrary JSON value. + * + * You should usually call [Builder.browserbaseSessionCreateParams] with a well-typed + * [BrowserbaseSessionCreateParams] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun browserbaseSessionCreateParams( + browserbaseSessionCreateParams: JsonField + ) = apply { body.browserbaseSessionCreateParams(browserbaseSessionCreateParams) } + + /** Existing Browserbase session ID to resume */ + fun browserbaseSessionId(browserbaseSessionId: String) = apply { + body.browserbaseSessionId(browserbaseSessionId) + } + + /** + * Sets [Builder.browserbaseSessionId] to an arbitrary JSON value. + * + * You should usually call [Builder.browserbaseSessionId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun browserbaseSessionId(browserbaseSessionId: JsonField) = apply { + body.browserbaseSessionId(browserbaseSessionId) + } + + fun debugDom(debugDom: Boolean) = apply { body.debugDom(debugDom) } + + /** + * Sets [Builder.debugDom] to an arbitrary JSON value. + * + * You should usually call [Builder.debugDom] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun debugDom(debugDom: JsonField) = apply { body.debugDom(debugDom) } + + /** Timeout in ms to wait for DOM to settle */ + fun domSettleTimeoutMs(domSettleTimeoutMs: Double) = apply { + body.domSettleTimeoutMs(domSettleTimeoutMs) + } + + /** + * Sets [Builder.domSettleTimeoutMs] to an arbitrary JSON value. + * + * You should usually call [Builder.domSettleTimeoutMs] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun domSettleTimeoutMs(domSettleTimeoutMs: JsonField) = apply { + body.domSettleTimeoutMs(domSettleTimeoutMs) + } + + fun experimental(experimental: Boolean) = apply { body.experimental(experimental) } + + /** + * Sets [Builder.experimental] to an arbitrary JSON value. + * + * You should usually call [Builder.experimental] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun experimental(experimental: JsonField) = apply { + body.experimental(experimental) + } + + /** Enable self-healing for failed actions */ + fun selfHeal(selfHeal: Boolean) = apply { body.selfHeal(selfHeal) } + + /** + * Sets [Builder.selfHeal] to an arbitrary JSON value. + * + * You should usually call [Builder.selfHeal] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun selfHeal(selfHeal: JsonField) = apply { body.selfHeal(selfHeal) } + + /** Custom system prompt for AI operations */ + fun systemPrompt(systemPrompt: String) = apply { body.systemPrompt(systemPrompt) } + + /** + * Sets [Builder.systemPrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.systemPrompt] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun systemPrompt(systemPrompt: JsonField) = apply { + body.systemPrompt(systemPrompt) + } + + /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ + fun verbose(verbose: Verbose) = apply { body.verbose(verbose) } + + /** + * Sets [Builder.verbose] to an arbitrary JSON value. + * + * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + + fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = apply { + body.waitForCaptchaSolves(waitForCaptchaSolves) + } + + /** + * Sets [Builder.waitForCaptchaSolves] to an arbitrary JSON value. + * + * You should usually call [Builder.waitForCaptchaSolves] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun waitForCaptchaSolves(waitForCaptchaSolves: JsonField) = apply { + body.waitForCaptchaSolves(waitForCaptchaSolves) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -201,6 +605,13 @@ private constructor( * Returns an immutable instance of [SessionStartParams]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): SessionStartParams = SessionStartParams( @@ -208,18 +619,7241 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, - body, + body.build(), additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): JsonValue = body + fun _body(): Body = body - override fun _headers(): Headers = Headers.builder().apply { putAll(additionalHeaders) }.build() + override fun _headers(): Headers = + Headers.builder() + .apply { + xLanguage?.let { put("x-language", it.toString()) } + xSdkVersion?.let { put("x-sdk-version", it) } + xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() override fun _queryParams(): QueryParams = additionalQueryParams + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val modelName: JsonField, + private val actTimeoutMs: JsonField, + private val browser: JsonField, + private val browserbaseSessionCreateParams: JsonField, + private val browserbaseSessionId: JsonField, + private val debugDom: JsonField, + private val domSettleTimeoutMs: JsonField, + private val experimental: JsonField, + private val selfHeal: JsonField, + private val systemPrompt: JsonField, + private val verbose: JsonField, + private val waitForCaptchaSolves: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("modelName") + @ExcludeMissing + modelName: JsonField = JsonMissing.of(), + @JsonProperty("actTimeoutMs") + @ExcludeMissing + actTimeoutMs: JsonField = JsonMissing.of(), + @JsonProperty("browser") @ExcludeMissing browser: JsonField = JsonMissing.of(), + @JsonProperty("browserbaseSessionCreateParams") + @ExcludeMissing + browserbaseSessionCreateParams: JsonField = + JsonMissing.of(), + @JsonProperty("browserbaseSessionID") + @ExcludeMissing + browserbaseSessionId: JsonField = JsonMissing.of(), + @JsonProperty("debugDom") + @ExcludeMissing + debugDom: JsonField = JsonMissing.of(), + @JsonProperty("domSettleTimeoutMs") + @ExcludeMissing + domSettleTimeoutMs: JsonField = JsonMissing.of(), + @JsonProperty("experimental") + @ExcludeMissing + experimental: JsonField = JsonMissing.of(), + @JsonProperty("selfHeal") + @ExcludeMissing + selfHeal: JsonField = JsonMissing.of(), + @JsonProperty("systemPrompt") + @ExcludeMissing + systemPrompt: JsonField = JsonMissing.of(), + @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), + @JsonProperty("waitForCaptchaSolves") + @ExcludeMissing + waitForCaptchaSolves: JsonField = JsonMissing.of(), + ) : this( + modelName, + actTimeoutMs, + browser, + browserbaseSessionCreateParams, + browserbaseSessionId, + debugDom, + domSettleTimeoutMs, + experimental, + selfHeal, + systemPrompt, + verbose, + waitForCaptchaSolves, + mutableMapOf(), + ) + + /** + * Model name to use for AI operations + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun modelName(): String = modelName.getRequired("modelName") + + /** + * Timeout in ms for act operations + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun actTimeoutMs(): Optional = actTimeoutMs.getOptional("actTimeoutMs") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun browser(): Optional = browser.getOptional("browser") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun browserbaseSessionCreateParams(): Optional = + browserbaseSessionCreateParams.getOptional("browserbaseSessionCreateParams") + + /** + * Existing Browserbase session ID to resume + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun browserbaseSessionId(): Optional = + browserbaseSessionId.getOptional("browserbaseSessionID") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun debugDom(): Optional = debugDom.getOptional("debugDom") + + /** + * Timeout in ms to wait for DOM to settle + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun domSettleTimeoutMs(): Optional = + domSettleTimeoutMs.getOptional("domSettleTimeoutMs") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun experimental(): Optional = experimental.getOptional("experimental") + + /** + * Enable self-healing for failed actions + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun selfHeal(): Optional = selfHeal.getOptional("selfHeal") + + /** + * Custom system prompt for AI operations + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun systemPrompt(): Optional = systemPrompt.getOptional("systemPrompt") + + /** + * Logging verbosity level (0=quiet, 1=normal, 2=debug) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun verbose(): Optional = verbose.getOptional("verbose") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun waitForCaptchaSolves(): Optional = + waitForCaptchaSolves.getOptional("waitForCaptchaSolves") + + /** + * Returns the raw JSON value of [modelName]. + * + * Unlike [modelName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("modelName") @ExcludeMissing fun _modelName(): JsonField = modelName + + /** + * Returns the raw JSON value of [actTimeoutMs]. + * + * Unlike [actTimeoutMs], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("actTimeoutMs") + @ExcludeMissing + fun _actTimeoutMs(): JsonField = actTimeoutMs + + /** + * Returns the raw JSON value of [browser]. + * + * Unlike [browser], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("browser") @ExcludeMissing fun _browser(): JsonField = browser + + /** + * Returns the raw JSON value of [browserbaseSessionCreateParams]. + * + * Unlike [browserbaseSessionCreateParams], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("browserbaseSessionCreateParams") + @ExcludeMissing + fun _browserbaseSessionCreateParams(): JsonField = + browserbaseSessionCreateParams + + /** + * Returns the raw JSON value of [browserbaseSessionId]. + * + * Unlike [browserbaseSessionId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("browserbaseSessionID") + @ExcludeMissing + fun _browserbaseSessionId(): JsonField = browserbaseSessionId + + /** + * Returns the raw JSON value of [debugDom]. + * + * Unlike [debugDom], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("debugDom") @ExcludeMissing fun _debugDom(): JsonField = debugDom + + /** + * Returns the raw JSON value of [domSettleTimeoutMs]. + * + * Unlike [domSettleTimeoutMs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("domSettleTimeoutMs") + @ExcludeMissing + fun _domSettleTimeoutMs(): JsonField = domSettleTimeoutMs + + /** + * Returns the raw JSON value of [experimental]. + * + * Unlike [experimental], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("experimental") + @ExcludeMissing + fun _experimental(): JsonField = experimental + + /** + * Returns the raw JSON value of [selfHeal]. + * + * Unlike [selfHeal], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("selfHeal") @ExcludeMissing fun _selfHeal(): JsonField = selfHeal + + /** + * Returns the raw JSON value of [systemPrompt]. + * + * Unlike [systemPrompt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("systemPrompt") + @ExcludeMissing + fun _systemPrompt(): JsonField = systemPrompt + + /** + * Returns the raw JSON value of [verbose]. + * + * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose + + /** + * Returns the raw JSON value of [waitForCaptchaSolves]. + * + * Unlike [waitForCaptchaSolves], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("waitForCaptchaSolves") + @ExcludeMissing + fun _waitForCaptchaSolves(): JsonField = waitForCaptchaSolves + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var modelName: JsonField? = null + private var actTimeoutMs: JsonField = JsonMissing.of() + private var browser: JsonField = JsonMissing.of() + private var browserbaseSessionCreateParams: JsonField = + JsonMissing.of() + private var browserbaseSessionId: JsonField = JsonMissing.of() + private var debugDom: JsonField = JsonMissing.of() + private var domSettleTimeoutMs: JsonField = JsonMissing.of() + private var experimental: JsonField = JsonMissing.of() + private var selfHeal: JsonField = JsonMissing.of() + private var systemPrompt: JsonField = JsonMissing.of() + private var verbose: JsonField = JsonMissing.of() + private var waitForCaptchaSolves: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + modelName = body.modelName + actTimeoutMs = body.actTimeoutMs + browser = body.browser + browserbaseSessionCreateParams = body.browserbaseSessionCreateParams + browserbaseSessionId = body.browserbaseSessionId + debugDom = body.debugDom + domSettleTimeoutMs = body.domSettleTimeoutMs + experimental = body.experimental + selfHeal = body.selfHeal + systemPrompt = body.systemPrompt + verbose = body.verbose + waitForCaptchaSolves = body.waitForCaptchaSolves + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** Model name to use for AI operations */ + fun modelName(modelName: String) = modelName(JsonField.of(modelName)) + + /** + * Sets [Builder.modelName] to an arbitrary JSON value. + * + * You should usually call [Builder.modelName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun modelName(modelName: JsonField) = apply { this.modelName = modelName } + + /** Timeout in ms for act operations */ + fun actTimeoutMs(actTimeoutMs: Double) = actTimeoutMs(JsonField.of(actTimeoutMs)) + + /** + * Sets [Builder.actTimeoutMs] to an arbitrary JSON value. + * + * You should usually call [Builder.actTimeoutMs] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun actTimeoutMs(actTimeoutMs: JsonField) = apply { + this.actTimeoutMs = actTimeoutMs + } + + fun browser(browser: Browser) = browser(JsonField.of(browser)) + + /** + * Sets [Builder.browser] to an arbitrary JSON value. + * + * You should usually call [Builder.browser] with a well-typed [Browser] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun browser(browser: JsonField) = apply { this.browser = browser } + + fun browserbaseSessionCreateParams( + browserbaseSessionCreateParams: BrowserbaseSessionCreateParams + ) = browserbaseSessionCreateParams(JsonField.of(browserbaseSessionCreateParams)) + + /** + * Sets [Builder.browserbaseSessionCreateParams] to an arbitrary JSON value. + * + * You should usually call [Builder.browserbaseSessionCreateParams] with a well-typed + * [BrowserbaseSessionCreateParams] value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun browserbaseSessionCreateParams( + browserbaseSessionCreateParams: JsonField + ) = apply { this.browserbaseSessionCreateParams = browserbaseSessionCreateParams } + + /** Existing Browserbase session ID to resume */ + fun browserbaseSessionId(browserbaseSessionId: String) = + browserbaseSessionId(JsonField.of(browserbaseSessionId)) + + /** + * Sets [Builder.browserbaseSessionId] to an arbitrary JSON value. + * + * You should usually call [Builder.browserbaseSessionId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun browserbaseSessionId(browserbaseSessionId: JsonField) = apply { + this.browserbaseSessionId = browserbaseSessionId + } + + fun debugDom(debugDom: Boolean) = debugDom(JsonField.of(debugDom)) + + /** + * Sets [Builder.debugDom] to an arbitrary JSON value. + * + * You should usually call [Builder.debugDom] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun debugDom(debugDom: JsonField) = apply { this.debugDom = debugDom } + + /** Timeout in ms to wait for DOM to settle */ + fun domSettleTimeoutMs(domSettleTimeoutMs: Double) = + domSettleTimeoutMs(JsonField.of(domSettleTimeoutMs)) + + /** + * Sets [Builder.domSettleTimeoutMs] to an arbitrary JSON value. + * + * You should usually call [Builder.domSettleTimeoutMs] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun domSettleTimeoutMs(domSettleTimeoutMs: JsonField) = apply { + this.domSettleTimeoutMs = domSettleTimeoutMs + } + + fun experimental(experimental: Boolean) = experimental(JsonField.of(experimental)) + + /** + * Sets [Builder.experimental] to an arbitrary JSON value. + * + * You should usually call [Builder.experimental] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun experimental(experimental: JsonField) = apply { + this.experimental = experimental + } + + /** Enable self-healing for failed actions */ + fun selfHeal(selfHeal: Boolean) = selfHeal(JsonField.of(selfHeal)) + + /** + * Sets [Builder.selfHeal] to an arbitrary JSON value. + * + * You should usually call [Builder.selfHeal] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun selfHeal(selfHeal: JsonField) = apply { this.selfHeal = selfHeal } + + /** Custom system prompt for AI operations */ + fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) + + /** + * Sets [Builder.systemPrompt] to an arbitrary JSON value. + * + * You should usually call [Builder.systemPrompt] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun systemPrompt(systemPrompt: JsonField) = apply { + this.systemPrompt = systemPrompt + } + + /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ + fun verbose(verbose: Verbose) = verbose(JsonField.of(verbose)) + + /** + * Sets [Builder.verbose] to an arbitrary JSON value. + * + * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + + fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = + waitForCaptchaSolves(JsonField.of(waitForCaptchaSolves)) + + /** + * Sets [Builder.waitForCaptchaSolves] to an arbitrary JSON value. + * + * You should usually call [Builder.waitForCaptchaSolves] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun waitForCaptchaSolves(waitForCaptchaSolves: JsonField) = apply { + this.waitForCaptchaSolves = waitForCaptchaSolves + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("modelName", modelName), + actTimeoutMs, + browser, + browserbaseSessionCreateParams, + browserbaseSessionId, + debugDom, + domSettleTimeoutMs, + experimental, + selfHeal, + systemPrompt, + verbose, + waitForCaptchaSolves, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + modelName() + actTimeoutMs() + browser().ifPresent { it.validate() } + browserbaseSessionCreateParams().ifPresent { it.validate() } + browserbaseSessionId() + debugDom() + domSettleTimeoutMs() + experimental() + selfHeal() + systemPrompt() + verbose().ifPresent { it.validate() } + waitForCaptchaSolves() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (modelName.asKnown().isPresent) 1 else 0) + + (if (actTimeoutMs.asKnown().isPresent) 1 else 0) + + (browser.asKnown().getOrNull()?.validity() ?: 0) + + (browserbaseSessionCreateParams.asKnown().getOrNull()?.validity() ?: 0) + + (if (browserbaseSessionId.asKnown().isPresent) 1 else 0) + + (if (debugDom.asKnown().isPresent) 1 else 0) + + (if (domSettleTimeoutMs.asKnown().isPresent) 1 else 0) + + (if (experimental.asKnown().isPresent) 1 else 0) + + (if (selfHeal.asKnown().isPresent) 1 else 0) + + (if (systemPrompt.asKnown().isPresent) 1 else 0) + + (verbose.asKnown().getOrNull()?.validity() ?: 0) + + (if (waitForCaptchaSolves.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + modelName == other.modelName && + actTimeoutMs == other.actTimeoutMs && + browser == other.browser && + browserbaseSessionCreateParams == other.browserbaseSessionCreateParams && + browserbaseSessionId == other.browserbaseSessionId && + debugDom == other.debugDom && + domSettleTimeoutMs == other.domSettleTimeoutMs && + experimental == other.experimental && + selfHeal == other.selfHeal && + systemPrompt == other.systemPrompt && + verbose == other.verbose && + waitForCaptchaSolves == other.waitForCaptchaSolves && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + modelName, + actTimeoutMs, + browser, + browserbaseSessionCreateParams, + browserbaseSessionId, + debugDom, + domSettleTimeoutMs, + experimental, + selfHeal, + systemPrompt, + verbose, + waitForCaptchaSolves, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, debugDom=$debugDom, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" + } + + class Browser + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cdpUrl: JsonField, + private val launchOptions: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cdpUrl") @ExcludeMissing cdpUrl: JsonField = JsonMissing.of(), + @JsonProperty("launchOptions") + @ExcludeMissing + launchOptions: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(cdpUrl, launchOptions, type, mutableMapOf()) + + /** + * Chrome DevTools Protocol URL for connecting to existing browser + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cdpUrl(): Optional = cdpUrl.getOptional("cdpUrl") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun launchOptions(): Optional = launchOptions.getOptional("launchOptions") + + /** + * Browser type to use + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * Returns the raw JSON value of [cdpUrl]. + * + * Unlike [cdpUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cdpUrl") @ExcludeMissing fun _cdpUrl(): JsonField = cdpUrl + + /** + * Returns the raw JSON value of [launchOptions]. + * + * Unlike [launchOptions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("launchOptions") + @ExcludeMissing + fun _launchOptions(): JsonField = launchOptions + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Browser]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Browser]. */ + class Builder internal constructor() { + + private var cdpUrl: JsonField = JsonMissing.of() + private var launchOptions: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(browser: Browser) = apply { + cdpUrl = browser.cdpUrl + launchOptions = browser.launchOptions + type = browser.type + additionalProperties = browser.additionalProperties.toMutableMap() + } + + /** Chrome DevTools Protocol URL for connecting to existing browser */ + fun cdpUrl(cdpUrl: String) = cdpUrl(JsonField.of(cdpUrl)) + + /** + * Sets [Builder.cdpUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.cdpUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cdpUrl(cdpUrl: JsonField) = apply { this.cdpUrl = cdpUrl } + + fun launchOptions(launchOptions: LaunchOptions) = + launchOptions(JsonField.of(launchOptions)) + + /** + * Sets [Builder.launchOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.launchOptions] with a well-typed [LaunchOptions] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun launchOptions(launchOptions: JsonField) = apply { + this.launchOptions = launchOptions + } + + /** Browser type to use */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Browser]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Browser = + Browser(cdpUrl, launchOptions, type, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Browser = apply { + if (validated) { + return@apply + } + + cdpUrl() + launchOptions().ifPresent { it.validate() } + type().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (cdpUrl.asKnown().isPresent) 1 else 0) + + (launchOptions.asKnown().getOrNull()?.validity() ?: 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + class LaunchOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val acceptDownloads: JsonField, + private val args: JsonField>, + private val cdpUrl: JsonField, + private val chromiumSandbox: JsonField, + private val connectTimeoutMs: JsonField, + private val deviceScaleFactor: JsonField, + private val devtools: JsonField, + private val downloadsPath: JsonField, + private val executablePath: JsonField, + private val hasTouch: JsonField, + private val headless: JsonField, + private val ignoreDefaultArgs: JsonField, + private val ignoreHttpsErrors: JsonField, + private val locale: JsonField, + private val preserveUserDataDir: JsonField, + private val proxy: JsonField, + private val userDataDir: JsonField, + private val viewport: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("acceptDownloads") + @ExcludeMissing + acceptDownloads: JsonField = JsonMissing.of(), + @JsonProperty("args") + @ExcludeMissing + args: JsonField> = JsonMissing.of(), + @JsonProperty("cdpUrl") + @ExcludeMissing + cdpUrl: JsonField = JsonMissing.of(), + @JsonProperty("chromiumSandbox") + @ExcludeMissing + chromiumSandbox: JsonField = JsonMissing.of(), + @JsonProperty("connectTimeoutMs") + @ExcludeMissing + connectTimeoutMs: JsonField = JsonMissing.of(), + @JsonProperty("deviceScaleFactor") + @ExcludeMissing + deviceScaleFactor: JsonField = JsonMissing.of(), + @JsonProperty("devtools") + @ExcludeMissing + devtools: JsonField = JsonMissing.of(), + @JsonProperty("downloadsPath") + @ExcludeMissing + downloadsPath: JsonField = JsonMissing.of(), + @JsonProperty("executablePath") + @ExcludeMissing + executablePath: JsonField = JsonMissing.of(), + @JsonProperty("hasTouch") + @ExcludeMissing + hasTouch: JsonField = JsonMissing.of(), + @JsonProperty("headless") + @ExcludeMissing + headless: JsonField = JsonMissing.of(), + @JsonProperty("ignoreDefaultArgs") + @ExcludeMissing + ignoreDefaultArgs: JsonField = JsonMissing.of(), + @JsonProperty("ignoreHTTPSErrors") + @ExcludeMissing + ignoreHttpsErrors: JsonField = JsonMissing.of(), + @JsonProperty("locale") + @ExcludeMissing + locale: JsonField = JsonMissing.of(), + @JsonProperty("preserveUserDataDir") + @ExcludeMissing + preserveUserDataDir: JsonField = JsonMissing.of(), + @JsonProperty("proxy") @ExcludeMissing proxy: JsonField = JsonMissing.of(), + @JsonProperty("userDataDir") + @ExcludeMissing + userDataDir: JsonField = JsonMissing.of(), + @JsonProperty("viewport") + @ExcludeMissing + viewport: JsonField = JsonMissing.of(), + ) : this( + acceptDownloads, + args, + cdpUrl, + chromiumSandbox, + connectTimeoutMs, + deviceScaleFactor, + devtools, + downloadsPath, + executablePath, + hasTouch, + headless, + ignoreDefaultArgs, + ignoreHttpsErrors, + locale, + preserveUserDataDir, + proxy, + userDataDir, + viewport, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun acceptDownloads(): Optional = + acceptDownloads.getOptional("acceptDownloads") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun args(): Optional> = args.getOptional("args") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun cdpUrl(): Optional = cdpUrl.getOptional("cdpUrl") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun chromiumSandbox(): Optional = + chromiumSandbox.getOptional("chromiumSandbox") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun connectTimeoutMs(): Optional = + connectTimeoutMs.getOptional("connectTimeoutMs") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun deviceScaleFactor(): Optional = + deviceScaleFactor.getOptional("deviceScaleFactor") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun devtools(): Optional = devtools.getOptional("devtools") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun downloadsPath(): Optional = downloadsPath.getOptional("downloadsPath") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun executablePath(): Optional = executablePath.getOptional("executablePath") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun hasTouch(): Optional = hasTouch.getOptional("hasTouch") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun headless(): Optional = headless.getOptional("headless") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun ignoreDefaultArgs(): Optional = + ignoreDefaultArgs.getOptional("ignoreDefaultArgs") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun ignoreHttpsErrors(): Optional = + ignoreHttpsErrors.getOptional("ignoreHTTPSErrors") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun locale(): Optional = locale.getOptional("locale") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun preserveUserDataDir(): Optional = + preserveUserDataDir.getOptional("preserveUserDataDir") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun proxy(): Optional = proxy.getOptional("proxy") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun userDataDir(): Optional = userDataDir.getOptional("userDataDir") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun viewport(): Optional = viewport.getOptional("viewport") + + /** + * Returns the raw JSON value of [acceptDownloads]. + * + * Unlike [acceptDownloads], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("acceptDownloads") + @ExcludeMissing + fun _acceptDownloads(): JsonField = acceptDownloads + + /** + * Returns the raw JSON value of [args]. + * + * Unlike [args], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("args") @ExcludeMissing fun _args(): JsonField> = args + + /** + * Returns the raw JSON value of [cdpUrl]. + * + * Unlike [cdpUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cdpUrl") @ExcludeMissing fun _cdpUrl(): JsonField = cdpUrl + + /** + * Returns the raw JSON value of [chromiumSandbox]. + * + * Unlike [chromiumSandbox], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("chromiumSandbox") + @ExcludeMissing + fun _chromiumSandbox(): JsonField = chromiumSandbox + + /** + * Returns the raw JSON value of [connectTimeoutMs]. + * + * Unlike [connectTimeoutMs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("connectTimeoutMs") + @ExcludeMissing + fun _connectTimeoutMs(): JsonField = connectTimeoutMs + + /** + * Returns the raw JSON value of [deviceScaleFactor]. + * + * Unlike [deviceScaleFactor], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("deviceScaleFactor") + @ExcludeMissing + fun _deviceScaleFactor(): JsonField = deviceScaleFactor + + /** + * Returns the raw JSON value of [devtools]. + * + * Unlike [devtools], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("devtools") @ExcludeMissing fun _devtools(): JsonField = devtools + + /** + * Returns the raw JSON value of [downloadsPath]. + * + * Unlike [downloadsPath], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("downloadsPath") + @ExcludeMissing + fun _downloadsPath(): JsonField = downloadsPath + + /** + * Returns the raw JSON value of [executablePath]. + * + * Unlike [executablePath], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("executablePath") + @ExcludeMissing + fun _executablePath(): JsonField = executablePath + + /** + * Returns the raw JSON value of [hasTouch]. + * + * Unlike [hasTouch], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("hasTouch") @ExcludeMissing fun _hasTouch(): JsonField = hasTouch + + /** + * Returns the raw JSON value of [headless]. + * + * Unlike [headless], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("headless") @ExcludeMissing fun _headless(): JsonField = headless + + /** + * Returns the raw JSON value of [ignoreDefaultArgs]. + * + * Unlike [ignoreDefaultArgs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("ignoreDefaultArgs") + @ExcludeMissing + fun _ignoreDefaultArgs(): JsonField = ignoreDefaultArgs + + /** + * Returns the raw JSON value of [ignoreHttpsErrors]. + * + * Unlike [ignoreHttpsErrors], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("ignoreHTTPSErrors") + @ExcludeMissing + fun _ignoreHttpsErrors(): JsonField = ignoreHttpsErrors + + /** + * Returns the raw JSON value of [locale]. + * + * Unlike [locale], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("locale") @ExcludeMissing fun _locale(): JsonField = locale + + /** + * Returns the raw JSON value of [preserveUserDataDir]. + * + * Unlike [preserveUserDataDir], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("preserveUserDataDir") + @ExcludeMissing + fun _preserveUserDataDir(): JsonField = preserveUserDataDir + + /** + * Returns the raw JSON value of [proxy]. + * + * Unlike [proxy], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("proxy") @ExcludeMissing fun _proxy(): JsonField = proxy + + /** + * Returns the raw JSON value of [userDataDir]. + * + * Unlike [userDataDir], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("userDataDir") + @ExcludeMissing + fun _userDataDir(): JsonField = userDataDir + + /** + * Returns the raw JSON value of [viewport]. + * + * Unlike [viewport], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("viewport") + @ExcludeMissing + fun _viewport(): JsonField = viewport + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [LaunchOptions]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LaunchOptions]. */ + class Builder internal constructor() { + + private var acceptDownloads: JsonField = JsonMissing.of() + private var args: JsonField>? = null + private var cdpUrl: JsonField = JsonMissing.of() + private var chromiumSandbox: JsonField = JsonMissing.of() + private var connectTimeoutMs: JsonField = JsonMissing.of() + private var deviceScaleFactor: JsonField = JsonMissing.of() + private var devtools: JsonField = JsonMissing.of() + private var downloadsPath: JsonField = JsonMissing.of() + private var executablePath: JsonField = JsonMissing.of() + private var hasTouch: JsonField = JsonMissing.of() + private var headless: JsonField = JsonMissing.of() + private var ignoreDefaultArgs: JsonField = JsonMissing.of() + private var ignoreHttpsErrors: JsonField = JsonMissing.of() + private var locale: JsonField = JsonMissing.of() + private var preserveUserDataDir: JsonField = JsonMissing.of() + private var proxy: JsonField = JsonMissing.of() + private var userDataDir: JsonField = JsonMissing.of() + private var viewport: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(launchOptions: LaunchOptions) = apply { + acceptDownloads = launchOptions.acceptDownloads + args = launchOptions.args.map { it.toMutableList() } + cdpUrl = launchOptions.cdpUrl + chromiumSandbox = launchOptions.chromiumSandbox + connectTimeoutMs = launchOptions.connectTimeoutMs + deviceScaleFactor = launchOptions.deviceScaleFactor + devtools = launchOptions.devtools + downloadsPath = launchOptions.downloadsPath + executablePath = launchOptions.executablePath + hasTouch = launchOptions.hasTouch + headless = launchOptions.headless + ignoreDefaultArgs = launchOptions.ignoreDefaultArgs + ignoreHttpsErrors = launchOptions.ignoreHttpsErrors + locale = launchOptions.locale + preserveUserDataDir = launchOptions.preserveUserDataDir + proxy = launchOptions.proxy + userDataDir = launchOptions.userDataDir + viewport = launchOptions.viewport + additionalProperties = launchOptions.additionalProperties.toMutableMap() + } + + fun acceptDownloads(acceptDownloads: Boolean) = + acceptDownloads(JsonField.of(acceptDownloads)) + + /** + * Sets [Builder.acceptDownloads] to an arbitrary JSON value. + * + * You should usually call [Builder.acceptDownloads] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun acceptDownloads(acceptDownloads: JsonField) = apply { + this.acceptDownloads = acceptDownloads + } + + fun args(args: List) = args(JsonField.of(args)) + + /** + * Sets [Builder.args] to an arbitrary JSON value. + * + * You should usually call [Builder.args] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun args(args: JsonField>) = apply { + this.args = args.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [args]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addArg(arg: String) = apply { + args = + (args ?: JsonField.of(mutableListOf())).also { + checkKnown("args", it).add(arg) + } + } + + fun cdpUrl(cdpUrl: String) = cdpUrl(JsonField.of(cdpUrl)) + + /** + * Sets [Builder.cdpUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.cdpUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun cdpUrl(cdpUrl: JsonField) = apply { this.cdpUrl = cdpUrl } + + fun chromiumSandbox(chromiumSandbox: Boolean) = + chromiumSandbox(JsonField.of(chromiumSandbox)) + + /** + * Sets [Builder.chromiumSandbox] to an arbitrary JSON value. + * + * You should usually call [Builder.chromiumSandbox] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun chromiumSandbox(chromiumSandbox: JsonField) = apply { + this.chromiumSandbox = chromiumSandbox + } + + fun connectTimeoutMs(connectTimeoutMs: Double) = + connectTimeoutMs(JsonField.of(connectTimeoutMs)) + + /** + * Sets [Builder.connectTimeoutMs] to an arbitrary JSON value. + * + * You should usually call [Builder.connectTimeoutMs] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun connectTimeoutMs(connectTimeoutMs: JsonField) = apply { + this.connectTimeoutMs = connectTimeoutMs + } + + fun deviceScaleFactor(deviceScaleFactor: Double) = + deviceScaleFactor(JsonField.of(deviceScaleFactor)) + + /** + * Sets [Builder.deviceScaleFactor] to an arbitrary JSON value. + * + * You should usually call [Builder.deviceScaleFactor] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun deviceScaleFactor(deviceScaleFactor: JsonField) = apply { + this.deviceScaleFactor = deviceScaleFactor + } + + fun devtools(devtools: Boolean) = devtools(JsonField.of(devtools)) + + /** + * Sets [Builder.devtools] to an arbitrary JSON value. + * + * You should usually call [Builder.devtools] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun devtools(devtools: JsonField) = apply { this.devtools = devtools } + + fun downloadsPath(downloadsPath: String) = + downloadsPath(JsonField.of(downloadsPath)) + + /** + * Sets [Builder.downloadsPath] to an arbitrary JSON value. + * + * You should usually call [Builder.downloadsPath] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun downloadsPath(downloadsPath: JsonField) = apply { + this.downloadsPath = downloadsPath + } + + fun executablePath(executablePath: String) = + executablePath(JsonField.of(executablePath)) + + /** + * Sets [Builder.executablePath] to an arbitrary JSON value. + * + * You should usually call [Builder.executablePath] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun executablePath(executablePath: JsonField) = apply { + this.executablePath = executablePath + } + + fun hasTouch(hasTouch: Boolean) = hasTouch(JsonField.of(hasTouch)) + + /** + * Sets [Builder.hasTouch] to an arbitrary JSON value. + * + * You should usually call [Builder.hasTouch] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun hasTouch(hasTouch: JsonField) = apply { this.hasTouch = hasTouch } + + fun headless(headless: Boolean) = headless(JsonField.of(headless)) + + /** + * Sets [Builder.headless] to an arbitrary JSON value. + * + * You should usually call [Builder.headless] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun headless(headless: JsonField) = apply { this.headless = headless } + + fun ignoreDefaultArgs(ignoreDefaultArgs: IgnoreDefaultArgs) = + ignoreDefaultArgs(JsonField.of(ignoreDefaultArgs)) + + /** + * Sets [Builder.ignoreDefaultArgs] to an arbitrary JSON value. + * + * You should usually call [Builder.ignoreDefaultArgs] with a well-typed + * [IgnoreDefaultArgs] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun ignoreDefaultArgs(ignoreDefaultArgs: JsonField) = apply { + this.ignoreDefaultArgs = ignoreDefaultArgs + } + + /** Alias for calling [ignoreDefaultArgs] with `IgnoreDefaultArgs.ofBool(bool)`. */ + fun ignoreDefaultArgs(bool: Boolean) = + ignoreDefaultArgs(IgnoreDefaultArgs.ofBool(bool)) + + /** + * Alias for calling [ignoreDefaultArgs] with + * `IgnoreDefaultArgs.ofStrings(strings)`. + */ + fun ignoreDefaultArgsOfStrings(strings: List) = + ignoreDefaultArgs(IgnoreDefaultArgs.ofStrings(strings)) + + fun ignoreHttpsErrors(ignoreHttpsErrors: Boolean) = + ignoreHttpsErrors(JsonField.of(ignoreHttpsErrors)) + + /** + * Sets [Builder.ignoreHttpsErrors] to an arbitrary JSON value. + * + * You should usually call [Builder.ignoreHttpsErrors] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun ignoreHttpsErrors(ignoreHttpsErrors: JsonField) = apply { + this.ignoreHttpsErrors = ignoreHttpsErrors + } + + fun locale(locale: String) = locale(JsonField.of(locale)) + + /** + * Sets [Builder.locale] to an arbitrary JSON value. + * + * You should usually call [Builder.locale] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun locale(locale: JsonField) = apply { this.locale = locale } + + fun preserveUserDataDir(preserveUserDataDir: Boolean) = + preserveUserDataDir(JsonField.of(preserveUserDataDir)) + + /** + * Sets [Builder.preserveUserDataDir] to an arbitrary JSON value. + * + * You should usually call [Builder.preserveUserDataDir] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun preserveUserDataDir(preserveUserDataDir: JsonField) = apply { + this.preserveUserDataDir = preserveUserDataDir + } + + fun proxy(proxy: Proxy) = proxy(JsonField.of(proxy)) + + /** + * Sets [Builder.proxy] to an arbitrary JSON value. + * + * You should usually call [Builder.proxy] with a well-typed [Proxy] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun proxy(proxy: JsonField) = apply { this.proxy = proxy } + + fun userDataDir(userDataDir: String) = userDataDir(JsonField.of(userDataDir)) + + /** + * Sets [Builder.userDataDir] to an arbitrary JSON value. + * + * You should usually call [Builder.userDataDir] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun userDataDir(userDataDir: JsonField) = apply { + this.userDataDir = userDataDir + } + + fun viewport(viewport: Viewport) = viewport(JsonField.of(viewport)) + + /** + * Sets [Builder.viewport] to an arbitrary JSON value. + * + * You should usually call [Builder.viewport] with a well-typed [Viewport] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun viewport(viewport: JsonField) = apply { this.viewport = viewport } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [LaunchOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): LaunchOptions = + LaunchOptions( + acceptDownloads, + (args ?: JsonMissing.of()).map { it.toImmutable() }, + cdpUrl, + chromiumSandbox, + connectTimeoutMs, + deviceScaleFactor, + devtools, + downloadsPath, + executablePath, + hasTouch, + headless, + ignoreDefaultArgs, + ignoreHttpsErrors, + locale, + preserveUserDataDir, + proxy, + userDataDir, + viewport, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): LaunchOptions = apply { + if (validated) { + return@apply + } + + acceptDownloads() + args() + cdpUrl() + chromiumSandbox() + connectTimeoutMs() + deviceScaleFactor() + devtools() + downloadsPath() + executablePath() + hasTouch() + headless() + ignoreDefaultArgs().ifPresent { it.validate() } + ignoreHttpsErrors() + locale() + preserveUserDataDir() + proxy().ifPresent { it.validate() } + userDataDir() + viewport().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (acceptDownloads.asKnown().isPresent) 1 else 0) + + (args.asKnown().getOrNull()?.size ?: 0) + + (if (cdpUrl.asKnown().isPresent) 1 else 0) + + (if (chromiumSandbox.asKnown().isPresent) 1 else 0) + + (if (connectTimeoutMs.asKnown().isPresent) 1 else 0) + + (if (deviceScaleFactor.asKnown().isPresent) 1 else 0) + + (if (devtools.asKnown().isPresent) 1 else 0) + + (if (downloadsPath.asKnown().isPresent) 1 else 0) + + (if (executablePath.asKnown().isPresent) 1 else 0) + + (if (hasTouch.asKnown().isPresent) 1 else 0) + + (if (headless.asKnown().isPresent) 1 else 0) + + (ignoreDefaultArgs.asKnown().getOrNull()?.validity() ?: 0) + + (if (ignoreHttpsErrors.asKnown().isPresent) 1 else 0) + + (if (locale.asKnown().isPresent) 1 else 0) + + (if (preserveUserDataDir.asKnown().isPresent) 1 else 0) + + (proxy.asKnown().getOrNull()?.validity() ?: 0) + + (if (userDataDir.asKnown().isPresent) 1 else 0) + + (viewport.asKnown().getOrNull()?.validity() ?: 0) + + @JsonDeserialize(using = IgnoreDefaultArgs.Deserializer::class) + @JsonSerialize(using = IgnoreDefaultArgs.Serializer::class) + class IgnoreDefaultArgs + private constructor( + private val bool: Boolean? = null, + private val strings: List? = null, + private val _json: JsonValue? = null, + ) { + + fun bool(): Optional = Optional.ofNullable(bool) + + fun strings(): Optional> = Optional.ofNullable(strings) + + fun isBool(): Boolean = bool != null + + fun isStrings(): Boolean = strings != null + + fun asBool(): Boolean = bool.getOrThrow("bool") + + fun asStrings(): List = strings.getOrThrow("strings") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + bool != null -> visitor.visitBool(bool) + strings != null -> visitor.visitStrings(strings) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): IgnoreDefaultArgs = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitBool(bool: Boolean) {} + + override fun visitStrings(strings: List) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBool(bool: Boolean) = 1 + + override fun visitStrings(strings: List) = strings.size + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is IgnoreDefaultArgs && + bool == other.bool && + strings == other.strings + } + + override fun hashCode(): Int = Objects.hash(bool, strings) + + override fun toString(): String = + when { + bool != null -> "IgnoreDefaultArgs{bool=$bool}" + strings != null -> "IgnoreDefaultArgs{strings=$strings}" + _json != null -> "IgnoreDefaultArgs{_unknown=$_json}" + else -> throw IllegalStateException("Invalid IgnoreDefaultArgs") + } + + companion object { + + @JvmStatic fun ofBool(bool: Boolean) = IgnoreDefaultArgs(bool = bool) + + @JvmStatic + fun ofStrings(strings: List) = + IgnoreDefaultArgs(strings = strings.toImmutable()) + } + + /** + * An interface that defines how to map each variant of [IgnoreDefaultArgs] to a + * value of type [T]. + */ + interface Visitor { + + fun visitBool(bool: Boolean): T + + fun visitStrings(strings: List): T + + /** + * Maps an unknown variant of [IgnoreDefaultArgs] to a value of type [T]. + * + * An instance of [IgnoreDefaultArgs] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if + * the SDK is on an older version than the API, then the API may respond with + * new variants that the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown IgnoreDefaultArgs: $json") + } + } + + internal class Deserializer : + BaseDeserializer(IgnoreDefaultArgs::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): IgnoreDefaultArgs { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + IgnoreDefaultArgs(bool = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>())?.let { + IgnoreDefaultArgs(strings = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely + // incompatible with all the possible variants (e.g. deserializing from + // string). + 0 -> IgnoreDefaultArgs(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use + // the first completely valid match, or simply the first match if none + // are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(IgnoreDefaultArgs::class) { + + override fun serialize( + value: IgnoreDefaultArgs, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.bool != null -> generator.writeObject(value.bool) + value.strings != null -> generator.writeObject(value.strings) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid IgnoreDefaultArgs") + } + } + } + } + + class Proxy + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val server: JsonField, + private val bypass: JsonField, + private val password: JsonField, + private val username: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("server") + @ExcludeMissing + server: JsonField = JsonMissing.of(), + @JsonProperty("bypass") + @ExcludeMissing + bypass: JsonField = JsonMissing.of(), + @JsonProperty("password") + @ExcludeMissing + password: JsonField = JsonMissing.of(), + @JsonProperty("username") + @ExcludeMissing + username: JsonField = JsonMissing.of(), + ) : this(server, bypass, password, username, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun server(): String = server.getRequired("server") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bypass(): Optional = bypass.getOptional("bypass") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun password(): Optional = password.getOptional("password") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun username(): Optional = username.getOptional("username") + + /** + * Returns the raw JSON value of [server]. + * + * Unlike [server], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("server") @ExcludeMissing fun _server(): JsonField = server + + /** + * Returns the raw JSON value of [bypass]. + * + * Unlike [bypass], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bypass") @ExcludeMissing fun _bypass(): JsonField = bypass + + /** + * Returns the raw JSON value of [password]. + * + * Unlike [password], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("password") + @ExcludeMissing + fun _password(): JsonField = password + + /** + * Returns the raw JSON value of [username]. + * + * Unlike [username], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("username") + @ExcludeMissing + fun _username(): JsonField = username + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Proxy]. + * + * The following fields are required: + * ```java + * .server() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Proxy]. */ + class Builder internal constructor() { + + private var server: JsonField? = null + private var bypass: JsonField = JsonMissing.of() + private var password: JsonField = JsonMissing.of() + private var username: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(proxy: Proxy) = apply { + server = proxy.server + bypass = proxy.bypass + password = proxy.password + username = proxy.username + additionalProperties = proxy.additionalProperties.toMutableMap() + } + + fun server(server: String) = server(JsonField.of(server)) + + /** + * Sets [Builder.server] to an arbitrary JSON value. + * + * You should usually call [Builder.server] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun server(server: JsonField) = apply { this.server = server } + + fun bypass(bypass: String) = bypass(JsonField.of(bypass)) + + /** + * Sets [Builder.bypass] to an arbitrary JSON value. + * + * You should usually call [Builder.bypass] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun bypass(bypass: JsonField) = apply { this.bypass = bypass } + + fun password(password: String) = password(JsonField.of(password)) + + /** + * Sets [Builder.password] to an arbitrary JSON value. + * + * You should usually call [Builder.password] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun password(password: JsonField) = apply { this.password = password } + + fun username(username: String) = username(JsonField.of(username)) + + /** + * Sets [Builder.username] to an arbitrary JSON value. + * + * You should usually call [Builder.username] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun username(username: JsonField) = apply { this.username = username } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Proxy]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .server() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Proxy = + Proxy( + checkRequired("server", server), + bypass, + password, + username, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Proxy = apply { + if (validated) { + return@apply + } + + server() + bypass() + password() + username() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (server.asKnown().isPresent) 1 else 0) + + (if (bypass.asKnown().isPresent) 1 else 0) + + (if (password.asKnown().isPresent) 1 else 0) + + (if (username.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Proxy && + server == other.server && + bypass == other.bypass && + password == other.password && + username == other.username && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(server, bypass, password, username, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Proxy{server=$server, bypass=$bypass, password=$password, username=$username, additionalProperties=$additionalProperties}" + } + + class Viewport + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val height: JsonField, + private val width: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("height") + @ExcludeMissing + height: JsonField = JsonMissing.of(), + @JsonProperty("width") + @ExcludeMissing + width: JsonField = JsonMissing.of(), + ) : this(height, width, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun height(): Double = height.getRequired("height") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun width(): Double = width.getRequired("width") + + /** + * Returns the raw JSON value of [height]. + * + * Unlike [height], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("height") @ExcludeMissing fun _height(): JsonField = height + + /** + * Returns the raw JSON value of [width]. + * + * Unlike [width], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("width") @ExcludeMissing fun _width(): JsonField = width + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Viewport]. + * + * The following fields are required: + * ```java + * .height() + * .width() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Viewport]. */ + class Builder internal constructor() { + + private var height: JsonField? = null + private var width: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(viewport: Viewport) = apply { + height = viewport.height + width = viewport.width + additionalProperties = viewport.additionalProperties.toMutableMap() + } + + fun height(height: Double) = height(JsonField.of(height)) + + /** + * Sets [Builder.height] to an arbitrary JSON value. + * + * You should usually call [Builder.height] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun height(height: JsonField) = apply { this.height = height } + + fun width(width: Double) = width(JsonField.of(width)) + + /** + * Sets [Builder.width] to an arbitrary JSON value. + * + * You should usually call [Builder.width] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun width(width: JsonField) = apply { this.width = width } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Viewport]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .height() + * .width() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Viewport = + Viewport( + checkRequired("height", height), + checkRequired("width", width), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Viewport = apply { + if (validated) { + return@apply + } + + height() + width() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (height.asKnown().isPresent) 1 else 0) + + (if (width.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Viewport && + height == other.height && + width == other.width && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(height, width, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Viewport{height=$height, width=$width, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is LaunchOptions && + acceptDownloads == other.acceptDownloads && + args == other.args && + cdpUrl == other.cdpUrl && + chromiumSandbox == other.chromiumSandbox && + connectTimeoutMs == other.connectTimeoutMs && + deviceScaleFactor == other.deviceScaleFactor && + devtools == other.devtools && + downloadsPath == other.downloadsPath && + executablePath == other.executablePath && + hasTouch == other.hasTouch && + headless == other.headless && + ignoreDefaultArgs == other.ignoreDefaultArgs && + ignoreHttpsErrors == other.ignoreHttpsErrors && + locale == other.locale && + preserveUserDataDir == other.preserveUserDataDir && + proxy == other.proxy && + userDataDir == other.userDataDir && + viewport == other.viewport && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + acceptDownloads, + args, + cdpUrl, + chromiumSandbox, + connectTimeoutMs, + deviceScaleFactor, + devtools, + downloadsPath, + executablePath, + hasTouch, + headless, + ignoreDefaultArgs, + ignoreHttpsErrors, + locale, + preserveUserDataDir, + proxy, + userDataDir, + viewport, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}" + } + + /** Browser type to use */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val LOCAL = of("local") + + @JvmField val BROWSERBASE = of("browserbase") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + LOCAL, + BROWSERBASE, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + LOCAL, + BROWSERBASE, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + LOCAL -> Value.LOCAL + BROWSERBASE -> Value.BROWSERBASE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + LOCAL -> Known.LOCAL + BROWSERBASE -> Known.BROWSERBASE + else -> throw StagehandInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Browser && + cdpUrl == other.cdpUrl && + launchOptions == other.launchOptions && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(cdpUrl, launchOptions, type, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Browser{cdpUrl=$cdpUrl, launchOptions=$launchOptions, type=$type, additionalProperties=$additionalProperties}" + } + + class BrowserbaseSessionCreateParams + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val browserSettings: JsonField, + private val extensionId: JsonField, + private val keepAlive: JsonField, + private val projectId: JsonField, + private val proxies: JsonField, + private val region: JsonField, + private val timeout: JsonField, + private val userMetadata: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("browserSettings") + @ExcludeMissing + browserSettings: JsonField = JsonMissing.of(), + @JsonProperty("extensionId") + @ExcludeMissing + extensionId: JsonField = JsonMissing.of(), + @JsonProperty("keepAlive") + @ExcludeMissing + keepAlive: JsonField = JsonMissing.of(), + @JsonProperty("projectId") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("proxies") @ExcludeMissing proxies: JsonField = JsonMissing.of(), + @JsonProperty("region") @ExcludeMissing region: JsonField = JsonMissing.of(), + @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), + @JsonProperty("userMetadata") + @ExcludeMissing + userMetadata: JsonField = JsonMissing.of(), + ) : this( + browserSettings, + extensionId, + keepAlive, + projectId, + proxies, + region, + timeout, + userMetadata, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun browserSettings(): Optional = + browserSettings.getOptional("browserSettings") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun extensionId(): Optional = extensionId.getOptional("extensionId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun keepAlive(): Optional = keepAlive.getOptional("keepAlive") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun projectId(): Optional = projectId.getOptional("projectId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun proxies(): Optional = proxies.getOptional("proxies") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun region(): Optional = region.getOptional("region") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun timeout(): Optional = timeout.getOptional("timeout") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun userMetadata(): Optional = userMetadata.getOptional("userMetadata") + + /** + * Returns the raw JSON value of [browserSettings]. + * + * Unlike [browserSettings], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("browserSettings") + @ExcludeMissing + fun _browserSettings(): JsonField = browserSettings + + /** + * Returns the raw JSON value of [extensionId]. + * + * Unlike [extensionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("extensionId") + @ExcludeMissing + fun _extensionId(): JsonField = extensionId + + /** + * Returns the raw JSON value of [keepAlive]. + * + * Unlike [keepAlive], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("keepAlive") @ExcludeMissing fun _keepAlive(): JsonField = keepAlive + + /** + * Returns the raw JSON value of [projectId]. + * + * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("projectId") @ExcludeMissing fun _projectId(): JsonField = projectId + + /** + * Returns the raw JSON value of [proxies]. + * + * Unlike [proxies], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("proxies") @ExcludeMissing fun _proxies(): JsonField = proxies + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region + + /** + * Returns the raw JSON value of [timeout]. + * + * Unlike [timeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + + /** + * Returns the raw JSON value of [userMetadata]. + * + * Unlike [userMetadata], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("userMetadata") + @ExcludeMissing + fun _userMetadata(): JsonField = userMetadata + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BrowserbaseSessionCreateParams]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BrowserbaseSessionCreateParams]. */ + class Builder internal constructor() { + + private var browserSettings: JsonField = JsonMissing.of() + private var extensionId: JsonField = JsonMissing.of() + private var keepAlive: JsonField = JsonMissing.of() + private var projectId: JsonField = JsonMissing.of() + private var proxies: JsonField = JsonMissing.of() + private var region: JsonField = JsonMissing.of() + private var timeout: JsonField = JsonMissing.of() + private var userMetadata: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(browserbaseSessionCreateParams: BrowserbaseSessionCreateParams) = + apply { + browserSettings = browserbaseSessionCreateParams.browserSettings + extensionId = browserbaseSessionCreateParams.extensionId + keepAlive = browserbaseSessionCreateParams.keepAlive + projectId = browserbaseSessionCreateParams.projectId + proxies = browserbaseSessionCreateParams.proxies + region = browserbaseSessionCreateParams.region + timeout = browserbaseSessionCreateParams.timeout + userMetadata = browserbaseSessionCreateParams.userMetadata + additionalProperties = + browserbaseSessionCreateParams.additionalProperties.toMutableMap() + } + + fun browserSettings(browserSettings: BrowserSettings) = + browserSettings(JsonField.of(browserSettings)) + + /** + * Sets [Builder.browserSettings] to an arbitrary JSON value. + * + * You should usually call [Builder.browserSettings] with a well-typed [BrowserSettings] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun browserSettings(browserSettings: JsonField) = apply { + this.browserSettings = browserSettings + } + + fun extensionId(extensionId: String) = extensionId(JsonField.of(extensionId)) + + /** + * Sets [Builder.extensionId] to an arbitrary JSON value. + * + * You should usually call [Builder.extensionId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun extensionId(extensionId: JsonField) = apply { + this.extensionId = extensionId + } + + fun keepAlive(keepAlive: Boolean) = keepAlive(JsonField.of(keepAlive)) + + /** + * Sets [Builder.keepAlive] to an arbitrary JSON value. + * + * You should usually call [Builder.keepAlive] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun keepAlive(keepAlive: JsonField) = apply { this.keepAlive = keepAlive } + + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) + + /** + * Sets [Builder.projectId] to an arbitrary JSON value. + * + * You should usually call [Builder.projectId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun projectId(projectId: JsonField) = apply { this.projectId = projectId } + + fun proxies(proxies: Proxies) = proxies(JsonField.of(proxies)) + + /** + * Sets [Builder.proxies] to an arbitrary JSON value. + * + * You should usually call [Builder.proxies] with a well-typed [Proxies] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun proxies(proxies: JsonField) = apply { this.proxies = proxies } + + /** Alias for calling [proxies] with `Proxies.ofBool(bool)`. */ + fun proxies(bool: Boolean) = proxies(Proxies.ofBool(bool)) + + /** + * Alias for calling [proxies] with + * `Proxies.ofUnnamedSchemaWithArrayParent0s(unnamedSchemaWithArrayParent0s)`. + */ + fun proxiesOfUnnamedSchemaWithArrayParent0s( + unnamedSchemaWithArrayParent0s: List + ) = proxies(Proxies.ofUnnamedSchemaWithArrayParent0s(unnamedSchemaWithArrayParent0s)) + + fun region(region: Region) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [Region] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) + + /** + * Sets [Builder.timeout] to an arbitrary JSON value. + * + * You should usually call [Builder.timeout] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + + fun userMetadata(userMetadata: UserMetadata) = userMetadata(JsonField.of(userMetadata)) + + /** + * Sets [Builder.userMetadata] to an arbitrary JSON value. + * + * You should usually call [Builder.userMetadata] with a well-typed [UserMetadata] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userMetadata(userMetadata: JsonField) = apply { + this.userMetadata = userMetadata + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BrowserbaseSessionCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BrowserbaseSessionCreateParams = + BrowserbaseSessionCreateParams( + browserSettings, + extensionId, + keepAlive, + projectId, + proxies, + region, + timeout, + userMetadata, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BrowserbaseSessionCreateParams = apply { + if (validated) { + return@apply + } + + browserSettings().ifPresent { it.validate() } + extensionId() + keepAlive() + projectId() + proxies().ifPresent { it.validate() } + region().ifPresent { it.validate() } + timeout() + userMetadata().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (browserSettings.asKnown().getOrNull()?.validity() ?: 0) + + (if (extensionId.asKnown().isPresent) 1 else 0) + + (if (keepAlive.asKnown().isPresent) 1 else 0) + + (if (projectId.asKnown().isPresent) 1 else 0) + + (proxies.asKnown().getOrNull()?.validity() ?: 0) + + (region.asKnown().getOrNull()?.validity() ?: 0) + + (if (timeout.asKnown().isPresent) 1 else 0) + + (userMetadata.asKnown().getOrNull()?.validity() ?: 0) + + class BrowserSettings + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val advancedStealth: JsonField, + private val blockAds: JsonField, + private val context: JsonField, + private val extensionId: JsonField, + private val fingerprint: JsonField, + private val logSession: JsonField, + private val recordSession: JsonField, + private val solveCaptchas: JsonField, + private val viewport: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("advancedStealth") + @ExcludeMissing + advancedStealth: JsonField = JsonMissing.of(), + @JsonProperty("blockAds") + @ExcludeMissing + blockAds: JsonField = JsonMissing.of(), + @JsonProperty("context") + @ExcludeMissing + context: JsonField = JsonMissing.of(), + @JsonProperty("extensionId") + @ExcludeMissing + extensionId: JsonField = JsonMissing.of(), + @JsonProperty("fingerprint") + @ExcludeMissing + fingerprint: JsonField = JsonMissing.of(), + @JsonProperty("logSession") + @ExcludeMissing + logSession: JsonField = JsonMissing.of(), + @JsonProperty("recordSession") + @ExcludeMissing + recordSession: JsonField = JsonMissing.of(), + @JsonProperty("solveCaptchas") + @ExcludeMissing + solveCaptchas: JsonField = JsonMissing.of(), + @JsonProperty("viewport") + @ExcludeMissing + viewport: JsonField = JsonMissing.of(), + ) : this( + advancedStealth, + blockAds, + context, + extensionId, + fingerprint, + logSession, + recordSession, + solveCaptchas, + viewport, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun advancedStealth(): Optional = + advancedStealth.getOptional("advancedStealth") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun blockAds(): Optional = blockAds.getOptional("blockAds") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun context(): Optional = context.getOptional("context") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun extensionId(): Optional = extensionId.getOptional("extensionId") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun fingerprint(): Optional = fingerprint.getOptional("fingerprint") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun logSession(): Optional = logSession.getOptional("logSession") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun recordSession(): Optional = recordSession.getOptional("recordSession") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun solveCaptchas(): Optional = solveCaptchas.getOptional("solveCaptchas") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun viewport(): Optional = viewport.getOptional("viewport") + + /** + * Returns the raw JSON value of [advancedStealth]. + * + * Unlike [advancedStealth], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("advancedStealth") + @ExcludeMissing + fun _advancedStealth(): JsonField = advancedStealth + + /** + * Returns the raw JSON value of [blockAds]. + * + * Unlike [blockAds], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("blockAds") @ExcludeMissing fun _blockAds(): JsonField = blockAds + + /** + * Returns the raw JSON value of [context]. + * + * Unlike [context], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("context") @ExcludeMissing fun _context(): JsonField = context + + /** + * Returns the raw JSON value of [extensionId]. + * + * Unlike [extensionId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("extensionId") + @ExcludeMissing + fun _extensionId(): JsonField = extensionId + + /** + * Returns the raw JSON value of [fingerprint]. + * + * Unlike [fingerprint], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("fingerprint") + @ExcludeMissing + fun _fingerprint(): JsonField = fingerprint + + /** + * Returns the raw JSON value of [logSession]. + * + * Unlike [logSession], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("logSession") + @ExcludeMissing + fun _logSession(): JsonField = logSession + + /** + * Returns the raw JSON value of [recordSession]. + * + * Unlike [recordSession], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("recordSession") + @ExcludeMissing + fun _recordSession(): JsonField = recordSession + + /** + * Returns the raw JSON value of [solveCaptchas]. + * + * Unlike [solveCaptchas], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("solveCaptchas") + @ExcludeMissing + fun _solveCaptchas(): JsonField = solveCaptchas + + /** + * Returns the raw JSON value of [viewport]. + * + * Unlike [viewport], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("viewport") + @ExcludeMissing + fun _viewport(): JsonField = viewport + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BrowserSettings]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BrowserSettings]. */ + class Builder internal constructor() { + + private var advancedStealth: JsonField = JsonMissing.of() + private var blockAds: JsonField = JsonMissing.of() + private var context: JsonField = JsonMissing.of() + private var extensionId: JsonField = JsonMissing.of() + private var fingerprint: JsonField = JsonMissing.of() + private var logSession: JsonField = JsonMissing.of() + private var recordSession: JsonField = JsonMissing.of() + private var solveCaptchas: JsonField = JsonMissing.of() + private var viewport: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(browserSettings: BrowserSettings) = apply { + advancedStealth = browserSettings.advancedStealth + blockAds = browserSettings.blockAds + context = browserSettings.context + extensionId = browserSettings.extensionId + fingerprint = browserSettings.fingerprint + logSession = browserSettings.logSession + recordSession = browserSettings.recordSession + solveCaptchas = browserSettings.solveCaptchas + viewport = browserSettings.viewport + additionalProperties = browserSettings.additionalProperties.toMutableMap() + } + + fun advancedStealth(advancedStealth: Boolean) = + advancedStealth(JsonField.of(advancedStealth)) + + /** + * Sets [Builder.advancedStealth] to an arbitrary JSON value. + * + * You should usually call [Builder.advancedStealth] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun advancedStealth(advancedStealth: JsonField) = apply { + this.advancedStealth = advancedStealth + } + + fun blockAds(blockAds: Boolean) = blockAds(JsonField.of(blockAds)) + + /** + * Sets [Builder.blockAds] to an arbitrary JSON value. + * + * You should usually call [Builder.blockAds] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun blockAds(blockAds: JsonField) = apply { this.blockAds = blockAds } + + fun context(context: Context) = context(JsonField.of(context)) + + /** + * Sets [Builder.context] to an arbitrary JSON value. + * + * You should usually call [Builder.context] with a well-typed [Context] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun context(context: JsonField) = apply { this.context = context } + + fun extensionId(extensionId: String) = extensionId(JsonField.of(extensionId)) + + /** + * Sets [Builder.extensionId] to an arbitrary JSON value. + * + * You should usually call [Builder.extensionId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun extensionId(extensionId: JsonField) = apply { + this.extensionId = extensionId + } + + fun fingerprint(fingerprint: Fingerprint) = fingerprint(JsonField.of(fingerprint)) + + /** + * Sets [Builder.fingerprint] to an arbitrary JSON value. + * + * You should usually call [Builder.fingerprint] with a well-typed [Fingerprint] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun fingerprint(fingerprint: JsonField) = apply { + this.fingerprint = fingerprint + } + + fun logSession(logSession: Boolean) = logSession(JsonField.of(logSession)) + + /** + * Sets [Builder.logSession] to an arbitrary JSON value. + * + * You should usually call [Builder.logSession] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun logSession(logSession: JsonField) = apply { + this.logSession = logSession + } + + fun recordSession(recordSession: Boolean) = + recordSession(JsonField.of(recordSession)) + + /** + * Sets [Builder.recordSession] to an arbitrary JSON value. + * + * You should usually call [Builder.recordSession] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun recordSession(recordSession: JsonField) = apply { + this.recordSession = recordSession + } + + fun solveCaptchas(solveCaptchas: Boolean) = + solveCaptchas(JsonField.of(solveCaptchas)) + + /** + * Sets [Builder.solveCaptchas] to an arbitrary JSON value. + * + * You should usually call [Builder.solveCaptchas] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun solveCaptchas(solveCaptchas: JsonField) = apply { + this.solveCaptchas = solveCaptchas + } + + fun viewport(viewport: Viewport) = viewport(JsonField.of(viewport)) + + /** + * Sets [Builder.viewport] to an arbitrary JSON value. + * + * You should usually call [Builder.viewport] with a well-typed [Viewport] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun viewport(viewport: JsonField) = apply { this.viewport = viewport } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BrowserSettings]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BrowserSettings = + BrowserSettings( + advancedStealth, + blockAds, + context, + extensionId, + fingerprint, + logSession, + recordSession, + solveCaptchas, + viewport, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BrowserSettings = apply { + if (validated) { + return@apply + } + + advancedStealth() + blockAds() + context().ifPresent { it.validate() } + extensionId() + fingerprint().ifPresent { it.validate() } + logSession() + recordSession() + solveCaptchas() + viewport().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (advancedStealth.asKnown().isPresent) 1 else 0) + + (if (blockAds.asKnown().isPresent) 1 else 0) + + (context.asKnown().getOrNull()?.validity() ?: 0) + + (if (extensionId.asKnown().isPresent) 1 else 0) + + (fingerprint.asKnown().getOrNull()?.validity() ?: 0) + + (if (logSession.asKnown().isPresent) 1 else 0) + + (if (recordSession.asKnown().isPresent) 1 else 0) + + (if (solveCaptchas.asKnown().isPresent) 1 else 0) + + (viewport.asKnown().getOrNull()?.validity() ?: 0) + + class Context + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val persist: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("persist") + @ExcludeMissing + persist: JsonField = JsonMissing.of(), + ) : this(id, persist, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun id(): String = id.getRequired("id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun persist(): Optional = persist.getOptional("persist") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [persist]. + * + * Unlike [persist], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("persist") + @ExcludeMissing + fun _persist(): JsonField = persist + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Context]. + * + * The following fields are required: + * ```java + * .id() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Context]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var persist: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(context: Context) = apply { + id = context.id + persist = context.persist + additionalProperties = context.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun persist(persist: Boolean) = persist(JsonField.of(persist)) + + /** + * Sets [Builder.persist] to an arbitrary JSON value. + * + * You should usually call [Builder.persist] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun persist(persist: JsonField) = apply { this.persist = persist } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Context]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Context = + Context( + checkRequired("id", id), + persist, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Context = apply { + if (validated) { + return@apply + } + + id() + persist() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (persist.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Context && + id == other.id && + persist == other.persist && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, persist, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Context{id=$id, persist=$persist, additionalProperties=$additionalProperties}" + } + + class Fingerprint + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val browsers: JsonField>, + private val devices: JsonField>, + private val httpVersion: JsonField, + private val locales: JsonField>, + private val operatingSystems: JsonField>, + private val screen: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("browsers") + @ExcludeMissing + browsers: JsonField> = JsonMissing.of(), + @JsonProperty("devices") + @ExcludeMissing + devices: JsonField> = JsonMissing.of(), + @JsonProperty("httpVersion") + @ExcludeMissing + httpVersion: JsonField = JsonMissing.of(), + @JsonProperty("locales") + @ExcludeMissing + locales: JsonField> = JsonMissing.of(), + @JsonProperty("operatingSystems") + @ExcludeMissing + operatingSystems: JsonField> = JsonMissing.of(), + @JsonProperty("screen") + @ExcludeMissing + screen: JsonField = JsonMissing.of(), + ) : this( + browsers, + devices, + httpVersion, + locales, + operatingSystems, + screen, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun browsers(): Optional> = browsers.getOptional("browsers") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun devices(): Optional> = devices.getOptional("devices") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun httpVersion(): Optional = httpVersion.getOptional("httpVersion") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun locales(): Optional> = locales.getOptional("locales") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun operatingSystems(): Optional> = + operatingSystems.getOptional("operatingSystems") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun screen(): Optional = screen.getOptional("screen") + + /** + * Returns the raw JSON value of [browsers]. + * + * Unlike [browsers], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("browsers") + @ExcludeMissing + fun _browsers(): JsonField> = browsers + + /** + * Returns the raw JSON value of [devices]. + * + * Unlike [devices], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("devices") + @ExcludeMissing + fun _devices(): JsonField> = devices + + /** + * Returns the raw JSON value of [httpVersion]. + * + * Unlike [httpVersion], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("httpVersion") + @ExcludeMissing + fun _httpVersion(): JsonField = httpVersion + + /** + * Returns the raw JSON value of [locales]. + * + * Unlike [locales], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("locales") + @ExcludeMissing + fun _locales(): JsonField> = locales + + /** + * Returns the raw JSON value of [operatingSystems]. + * + * Unlike [operatingSystems], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("operatingSystems") + @ExcludeMissing + fun _operatingSystems(): JsonField> = operatingSystems + + /** + * Returns the raw JSON value of [screen]. + * + * Unlike [screen], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("screen") @ExcludeMissing fun _screen(): JsonField = screen + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Fingerprint]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Fingerprint]. */ + class Builder internal constructor() { + + private var browsers: JsonField>? = null + private var devices: JsonField>? = null + private var httpVersion: JsonField = JsonMissing.of() + private var locales: JsonField>? = null + private var operatingSystems: JsonField>? = null + private var screen: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(fingerprint: Fingerprint) = apply { + browsers = fingerprint.browsers.map { it.toMutableList() } + devices = fingerprint.devices.map { it.toMutableList() } + httpVersion = fingerprint.httpVersion + locales = fingerprint.locales.map { it.toMutableList() } + operatingSystems = fingerprint.operatingSystems.map { it.toMutableList() } + screen = fingerprint.screen + additionalProperties = fingerprint.additionalProperties.toMutableMap() + } + + fun browsers(browsers: List) = browsers(JsonField.of(browsers)) + + /** + * Sets [Builder.browsers] to an arbitrary JSON value. + * + * You should usually call [Builder.browsers] with a well-typed `List` + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun browsers(browsers: JsonField>) = apply { + this.browsers = browsers.map { it.toMutableList() } + } + + /** + * Adds a single [Browser] to [browsers]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addBrowser(browser: Browser) = apply { + browsers = + (browsers ?: JsonField.of(mutableListOf())).also { + checkKnown("browsers", it).add(browser) + } + } + + fun devices(devices: List) = devices(JsonField.of(devices)) + + /** + * Sets [Builder.devices] to an arbitrary JSON value. + * + * You should usually call [Builder.devices] with a well-typed `List` + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun devices(devices: JsonField>) = apply { + this.devices = devices.map { it.toMutableList() } + } + + /** + * Adds a single [Device] to [devices]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addDevice(device: Device) = apply { + devices = + (devices ?: JsonField.of(mutableListOf())).also { + checkKnown("devices", it).add(device) + } + } + + fun httpVersion(httpVersion: HttpVersion) = + httpVersion(JsonField.of(httpVersion)) + + /** + * Sets [Builder.httpVersion] to an arbitrary JSON value. + * + * You should usually call [Builder.httpVersion] with a well-typed [HttpVersion] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun httpVersion(httpVersion: JsonField) = apply { + this.httpVersion = httpVersion + } + + fun locales(locales: List) = locales(JsonField.of(locales)) + + /** + * Sets [Builder.locales] to an arbitrary JSON value. + * + * You should usually call [Builder.locales] with a well-typed `List` + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun locales(locales: JsonField>) = apply { + this.locales = locales.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [locales]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addLocale(locale: String) = apply { + locales = + (locales ?: JsonField.of(mutableListOf())).also { + checkKnown("locales", it).add(locale) + } + } + + fun operatingSystems(operatingSystems: List) = + operatingSystems(JsonField.of(operatingSystems)) + + /** + * Sets [Builder.operatingSystems] to an arbitrary JSON value. + * + * You should usually call [Builder.operatingSystems] with a well-typed + * `List` value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun operatingSystems(operatingSystems: JsonField>) = + apply { + this.operatingSystems = operatingSystems.map { it.toMutableList() } + } + + /** + * Adds a single [OperatingSystem] to [operatingSystems]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addOperatingSystem(operatingSystem: OperatingSystem) = apply { + operatingSystems = + (operatingSystems ?: JsonField.of(mutableListOf())).also { + checkKnown("operatingSystems", it).add(operatingSystem) + } + } + + fun screen(screen: Screen) = screen(JsonField.of(screen)) + + /** + * Sets [Builder.screen] to an arbitrary JSON value. + * + * You should usually call [Builder.screen] with a well-typed [Screen] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun screen(screen: JsonField) = apply { this.screen = screen } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Fingerprint]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Fingerprint = + Fingerprint( + (browsers ?: JsonMissing.of()).map { it.toImmutable() }, + (devices ?: JsonMissing.of()).map { it.toImmutable() }, + httpVersion, + (locales ?: JsonMissing.of()).map { it.toImmutable() }, + (operatingSystems ?: JsonMissing.of()).map { it.toImmutable() }, + screen, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Fingerprint = apply { + if (validated) { + return@apply + } + + browsers().ifPresent { it.forEach { it.validate() } } + devices().ifPresent { it.forEach { it.validate() } } + httpVersion().ifPresent { it.validate() } + locales() + operatingSystems().ifPresent { it.forEach { it.validate() } } + screen().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (browsers.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (devices.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (httpVersion.asKnown().getOrNull()?.validity() ?: 0) + + (locales.asKnown().getOrNull()?.size ?: 0) + + (operatingSystems.asKnown().getOrNull()?.sumOf { it.validity().toInt() } + ?: 0) + + (screen.asKnown().getOrNull()?.validity() ?: 0) + + class Browser + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val CHROME = of("chrome") + + @JvmField val EDGE = of("edge") + + @JvmField val FIREFOX = of("firefox") + + @JvmField val SAFARI = of("safari") + + @JvmStatic fun of(value: String) = Browser(JsonField.of(value)) + } + + /** An enum containing [Browser]'s known values. */ + enum class Known { + CHROME, + EDGE, + FIREFOX, + SAFARI, + } + + /** + * An enum containing [Browser]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Browser] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + CHROME, + EDGE, + FIREFOX, + SAFARI, + /** + * An enum member indicating that [Browser] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or + * if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + CHROME -> Value.CHROME + EDGE -> Value.EDGE + FIREFOX -> Value.FIREFOX + SAFARI -> Value.SAFARI + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known + * and don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not + * a known member. + */ + fun known(): Known = + when (this) { + CHROME -> Known.CHROME + EDGE -> Known.EDGE + FIREFOX -> Known.FIREFOX + SAFARI -> Known.SAFARI + else -> throw StagehandInvalidDataException("Unknown Browser: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Browser = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Browser && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Device + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val DESKTOP = of("desktop") + + @JvmField val MOBILE = of("mobile") + + @JvmStatic fun of(value: String) = Device(JsonField.of(value)) + } + + /** An enum containing [Device]'s known values. */ + enum class Known { + DESKTOP, + MOBILE, + } + + /** + * An enum containing [Device]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Device] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + DESKTOP, + MOBILE, + /** + * An enum member indicating that [Device] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or + * if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + DESKTOP -> Value.DESKTOP + MOBILE -> Value.MOBILE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known + * and don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not + * a known member. + */ + fun known(): Known = + when (this) { + DESKTOP -> Known.DESKTOP + MOBILE -> Known.MOBILE + else -> throw StagehandInvalidDataException("Unknown Device: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Device = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Device && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class HttpVersion + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val _1 = of("1") + + @JvmField val _2 = of("2") + + @JvmStatic fun of(value: String) = HttpVersion(JsonField.of(value)) + } + + /** An enum containing [HttpVersion]'s known values. */ + enum class Known { + _1, + _2, + } + + /** + * An enum containing [HttpVersion]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [HttpVersion] can contain an unknown value in a couple of + * cases: + * - It was deserialized from data that doesn't match any known member. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + _1, + _2, + /** + * An enum member indicating that [HttpVersion] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or + * if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + _1 -> Value._1 + _2 -> Value._2 + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known + * and don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not + * a known member. + */ + fun known(): Known = + when (this) { + _1 -> Known._1 + _2 -> Known._2 + else -> + throw StagehandInvalidDataException("Unknown HttpVersion: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): HttpVersion = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is HttpVersion && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class OperatingSystem + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val ANDROID = of("android") + + @JvmField val IOS = of("ios") + + @JvmField val LINUX = of("linux") + + @JvmField val MACOS = of("macos") + + @JvmField val WINDOWS = of("windows") + + @JvmStatic fun of(value: String) = OperatingSystem(JsonField.of(value)) + } + + /** An enum containing [OperatingSystem]'s known values. */ + enum class Known { + ANDROID, + IOS, + LINUX, + MACOS, + WINDOWS, + } + + /** + * An enum containing [OperatingSystem]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [OperatingSystem] can contain an unknown value in a couple of + * cases: + * - It was deserialized from data that doesn't match any known member. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + ANDROID, + IOS, + LINUX, + MACOS, + WINDOWS, + /** + * An enum member indicating that [OperatingSystem] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or + * if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + ANDROID -> Value.ANDROID + IOS -> Value.IOS + LINUX -> Value.LINUX + MACOS -> Value.MACOS + WINDOWS -> Value.WINDOWS + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known + * and don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not + * a known member. + */ + fun known(): Known = + when (this) { + ANDROID -> Known.ANDROID + IOS -> Known.IOS + LINUX -> Known.LINUX + MACOS -> Known.MACOS + WINDOWS -> Known.WINDOWS + else -> + throw StagehandInvalidDataException( + "Unknown OperatingSystem: $value" + ) + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): OperatingSystem = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is OperatingSystem && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Screen + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val maxHeight: JsonField, + private val maxWidth: JsonField, + private val minHeight: JsonField, + private val minWidth: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("maxHeight") + @ExcludeMissing + maxHeight: JsonField = JsonMissing.of(), + @JsonProperty("maxWidth") + @ExcludeMissing + maxWidth: JsonField = JsonMissing.of(), + @JsonProperty("minHeight") + @ExcludeMissing + minHeight: JsonField = JsonMissing.of(), + @JsonProperty("minWidth") + @ExcludeMissing + minWidth: JsonField = JsonMissing.of(), + ) : this(maxHeight, maxWidth, minHeight, minWidth, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun maxHeight(): Optional = maxHeight.getOptional("maxHeight") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun maxWidth(): Optional = maxWidth.getOptional("maxWidth") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun minHeight(): Optional = minHeight.getOptional("minHeight") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun minWidth(): Optional = minWidth.getOptional("minWidth") + + /** + * Returns the raw JSON value of [maxHeight]. + * + * Unlike [maxHeight], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("maxHeight") + @ExcludeMissing + fun _maxHeight(): JsonField = maxHeight + + /** + * Returns the raw JSON value of [maxWidth]. + * + * Unlike [maxWidth], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("maxWidth") + @ExcludeMissing + fun _maxWidth(): JsonField = maxWidth + + /** + * Returns the raw JSON value of [minHeight]. + * + * Unlike [minHeight], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("minHeight") + @ExcludeMissing + fun _minHeight(): JsonField = minHeight + + /** + * Returns the raw JSON value of [minWidth]. + * + * Unlike [minWidth], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("minWidth") + @ExcludeMissing + fun _minWidth(): JsonField = minWidth + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Screen]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Screen]. */ + class Builder internal constructor() { + + private var maxHeight: JsonField = JsonMissing.of() + private var maxWidth: JsonField = JsonMissing.of() + private var minHeight: JsonField = JsonMissing.of() + private var minWidth: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(screen: Screen) = apply { + maxHeight = screen.maxHeight + maxWidth = screen.maxWidth + minHeight = screen.minHeight + minWidth = screen.minWidth + additionalProperties = screen.additionalProperties.toMutableMap() + } + + fun maxHeight(maxHeight: Double) = maxHeight(JsonField.of(maxHeight)) + + /** + * Sets [Builder.maxHeight] to an arbitrary JSON value. + * + * You should usually call [Builder.maxHeight] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun maxHeight(maxHeight: JsonField) = apply { + this.maxHeight = maxHeight + } + + fun maxWidth(maxWidth: Double) = maxWidth(JsonField.of(maxWidth)) + + /** + * Sets [Builder.maxWidth] to an arbitrary JSON value. + * + * You should usually call [Builder.maxWidth] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun maxWidth(maxWidth: JsonField) = apply { + this.maxWidth = maxWidth + } + + fun minHeight(minHeight: Double) = minHeight(JsonField.of(minHeight)) + + /** + * Sets [Builder.minHeight] to an arbitrary JSON value. + * + * You should usually call [Builder.minHeight] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun minHeight(minHeight: JsonField) = apply { + this.minHeight = minHeight + } + + fun minWidth(minWidth: Double) = minWidth(JsonField.of(minWidth)) + + /** + * Sets [Builder.minWidth] to an arbitrary JSON value. + * + * You should usually call [Builder.minWidth] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun minWidth(minWidth: JsonField) = apply { + this.minWidth = minWidth + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Screen]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Screen = + Screen( + maxHeight, + maxWidth, + minHeight, + minWidth, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Screen = apply { + if (validated) { + return@apply + } + + maxHeight() + maxWidth() + minHeight() + minWidth() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (maxHeight.asKnown().isPresent) 1 else 0) + + (if (maxWidth.asKnown().isPresent) 1 else 0) + + (if (minHeight.asKnown().isPresent) 1 else 0) + + (if (minWidth.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Screen && + maxHeight == other.maxHeight && + maxWidth == other.maxWidth && + minHeight == other.minHeight && + minWidth == other.minWidth && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(maxHeight, maxWidth, minHeight, minWidth, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Screen{maxHeight=$maxHeight, maxWidth=$maxWidth, minHeight=$minHeight, minWidth=$minWidth, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Fingerprint && + browsers == other.browsers && + devices == other.devices && + httpVersion == other.httpVersion && + locales == other.locales && + operatingSystems == other.operatingSystems && + screen == other.screen && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + browsers, + devices, + httpVersion, + locales, + operatingSystems, + screen, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Fingerprint{browsers=$browsers, devices=$devices, httpVersion=$httpVersion, locales=$locales, operatingSystems=$operatingSystems, screen=$screen, additionalProperties=$additionalProperties}" + } + + class Viewport + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val height: JsonField, + private val width: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("height") + @ExcludeMissing + height: JsonField = JsonMissing.of(), + @JsonProperty("width") + @ExcludeMissing + width: JsonField = JsonMissing.of(), + ) : this(height, width, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun height(): Optional = height.getOptional("height") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun width(): Optional = width.getOptional("width") + + /** + * Returns the raw JSON value of [height]. + * + * Unlike [height], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("height") @ExcludeMissing fun _height(): JsonField = height + + /** + * Returns the raw JSON value of [width]. + * + * Unlike [width], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("width") @ExcludeMissing fun _width(): JsonField = width + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Viewport]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Viewport]. */ + class Builder internal constructor() { + + private var height: JsonField = JsonMissing.of() + private var width: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(viewport: Viewport) = apply { + height = viewport.height + width = viewport.width + additionalProperties = viewport.additionalProperties.toMutableMap() + } + + fun height(height: Double) = height(JsonField.of(height)) + + /** + * Sets [Builder.height] to an arbitrary JSON value. + * + * You should usually call [Builder.height] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun height(height: JsonField) = apply { this.height = height } + + fun width(width: Double) = width(JsonField.of(width)) + + /** + * Sets [Builder.width] to an arbitrary JSON value. + * + * You should usually call [Builder.width] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun width(width: JsonField) = apply { this.width = width } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Viewport]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Viewport = + Viewport(height, width, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Viewport = apply { + if (validated) { + return@apply + } + + height() + width() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (height.asKnown().isPresent) 1 else 0) + + (if (width.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Viewport && + height == other.height && + width == other.width && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(height, width, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Viewport{height=$height, width=$width, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BrowserSettings && + advancedStealth == other.advancedStealth && + blockAds == other.blockAds && + context == other.context && + extensionId == other.extensionId && + fingerprint == other.fingerprint && + logSession == other.logSession && + recordSession == other.recordSession && + solveCaptchas == other.solveCaptchas && + viewport == other.viewport && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + advancedStealth, + blockAds, + context, + extensionId, + fingerprint, + logSession, + recordSession, + solveCaptchas, + viewport, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BrowserSettings{advancedStealth=$advancedStealth, blockAds=$blockAds, context=$context, extensionId=$extensionId, fingerprint=$fingerprint, logSession=$logSession, recordSession=$recordSession, solveCaptchas=$solveCaptchas, viewport=$viewport, additionalProperties=$additionalProperties}" + } + + @JsonDeserialize(using = Proxies.Deserializer::class) + @JsonSerialize(using = Proxies.Serializer::class) + class Proxies + private constructor( + private val bool: Boolean? = null, + private val unnamedSchemaWithArrayParent0s: List? = null, + private val _json: JsonValue? = null, + ) { + + fun bool(): Optional = Optional.ofNullable(bool) + + fun unnamedSchemaWithArrayParent0s(): Optional> = + Optional.ofNullable(unnamedSchemaWithArrayParent0s) + + fun isBool(): Boolean = bool != null + + fun isUnnamedSchemaWithArrayParent0s(): Boolean = unnamedSchemaWithArrayParent0s != null + + fun asBool(): Boolean = bool.getOrThrow("bool") + + fun asUnnamedSchemaWithArrayParent0s(): List = + unnamedSchemaWithArrayParent0s.getOrThrow("unnamedSchemaWithArrayParent0s") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + bool != null -> visitor.visitBool(bool) + unnamedSchemaWithArrayParent0s != null -> + visitor.visitUnnamedSchemaWithArrayParent0s(unnamedSchemaWithArrayParent0s) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Proxies = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitBool(bool: Boolean) {} + + override fun visitUnnamedSchemaWithArrayParent0s( + unnamedSchemaWithArrayParent0s: List + ) { + unnamedSchemaWithArrayParent0s.forEach { it.validate() } + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBool(bool: Boolean) = 1 + + override fun visitUnnamedSchemaWithArrayParent0s( + unnamedSchemaWithArrayParent0s: List + ) = unnamedSchemaWithArrayParent0s.sumOf { it.validity().toInt() } + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Proxies && + bool == other.bool && + unnamedSchemaWithArrayParent0s == other.unnamedSchemaWithArrayParent0s + } + + override fun hashCode(): Int = Objects.hash(bool, unnamedSchemaWithArrayParent0s) + + override fun toString(): String = + when { + bool != null -> "Proxies{bool=$bool}" + unnamedSchemaWithArrayParent0s != null -> + "Proxies{unnamedSchemaWithArrayParent0s=$unnamedSchemaWithArrayParent0s}" + _json != null -> "Proxies{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Proxies") + } + + companion object { + + @JvmStatic fun ofBool(bool: Boolean) = Proxies(bool = bool) + + @JvmStatic + fun ofUnnamedSchemaWithArrayParent0s( + unnamedSchemaWithArrayParent0s: List + ) = + Proxies( + unnamedSchemaWithArrayParent0s = + unnamedSchemaWithArrayParent0s.toImmutable() + ) + } + + /** + * An interface that defines how to map each variant of [Proxies] to a value of type + * [T]. + */ + interface Visitor { + + fun visitBool(bool: Boolean): T + + fun visitUnnamedSchemaWithArrayParent0s( + unnamedSchemaWithArrayParent0s: List + ): T + + /** + * Maps an unknown variant of [Proxies] to a value of type [T]. + * + * An instance of [Proxies] can contain an unknown variant if it was deserialized + * from data that doesn't match any known variant. For example, if the SDK is on an + * older version than the API, then the API may respond with new variants that the + * SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Proxies: $json") + } + } + + internal class Deserializer : BaseDeserializer(Proxies::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Proxies { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Proxies(bool = it, _json = json) + }, + tryDeserialize( + node, + jacksonTypeRef>(), + ) + ?.let { + Proxies(unnamedSchemaWithArrayParent0s = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from string). + 0 -> Proxies(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Proxies::class) { + + override fun serialize( + value: Proxies, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.bool != null -> generator.writeObject(value.bool) + value.unnamedSchemaWithArrayParent0s != null -> + generator.writeObject(value.unnamedSchemaWithArrayParent0s) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Proxies") + } + } + } + + @JsonDeserialize(using = UnnamedSchemaWithArrayParent0.Deserializer::class) + @JsonSerialize(using = UnnamedSchemaWithArrayParent0.Serializer::class) + class UnnamedSchemaWithArrayParent0 + private constructor( + private val browserbaseProxyConfig: BrowserbaseProxyConfig? = null, + private val externalProxyConfig: ExternalProxyConfig? = null, + private val _json: JsonValue? = null, + ) { + + fun browserbaseProxyConfig(): Optional = + Optional.ofNullable(browserbaseProxyConfig) + + fun externalProxyConfig(): Optional = + Optional.ofNullable(externalProxyConfig) + + fun isBrowserbaseProxyConfig(): Boolean = browserbaseProxyConfig != null + + fun isExternalProxyConfig(): Boolean = externalProxyConfig != null + + fun asBrowserbaseProxyConfig(): BrowserbaseProxyConfig = + browserbaseProxyConfig.getOrThrow("browserbaseProxyConfig") + + fun asExternalProxyConfig(): ExternalProxyConfig = + externalProxyConfig.getOrThrow("externalProxyConfig") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + browserbaseProxyConfig != null -> + visitor.visitBrowserbaseProxyConfig(browserbaseProxyConfig) + externalProxyConfig != null -> + visitor.visitExternalProxyConfig(externalProxyConfig) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): UnnamedSchemaWithArrayParent0 = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitBrowserbaseProxyConfig( + browserbaseProxyConfig: BrowserbaseProxyConfig + ) { + browserbaseProxyConfig.validate() + } + + override fun visitExternalProxyConfig( + externalProxyConfig: ExternalProxyConfig + ) { + externalProxyConfig.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBrowserbaseProxyConfig( + browserbaseProxyConfig: BrowserbaseProxyConfig + ) = browserbaseProxyConfig.validity() + + override fun visitExternalProxyConfig( + externalProxyConfig: ExternalProxyConfig + ) = externalProxyConfig.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is UnnamedSchemaWithArrayParent0 && + browserbaseProxyConfig == other.browserbaseProxyConfig && + externalProxyConfig == other.externalProxyConfig + } + + override fun hashCode(): Int = + Objects.hash(browserbaseProxyConfig, externalProxyConfig) + + override fun toString(): String = + when { + browserbaseProxyConfig != null -> + "UnnamedSchemaWithArrayParent0{browserbaseProxyConfig=$browserbaseProxyConfig}" + externalProxyConfig != null -> + "UnnamedSchemaWithArrayParent0{externalProxyConfig=$externalProxyConfig}" + _json != null -> "UnnamedSchemaWithArrayParent0{_unknown=$_json}" + else -> throw IllegalStateException("Invalid UnnamedSchemaWithArrayParent0") + } + + companion object { + + @JvmStatic + fun ofBrowserbaseProxyConfig(browserbaseProxyConfig: BrowserbaseProxyConfig) = + UnnamedSchemaWithArrayParent0( + browserbaseProxyConfig = browserbaseProxyConfig + ) + + @JvmStatic + fun ofExternalProxyConfig(externalProxyConfig: ExternalProxyConfig) = + UnnamedSchemaWithArrayParent0(externalProxyConfig = externalProxyConfig) + } + + /** + * An interface that defines how to map each variant of + * [UnnamedSchemaWithArrayParent0] to a value of type [T]. + */ + interface Visitor { + + fun visitBrowserbaseProxyConfig( + browserbaseProxyConfig: BrowserbaseProxyConfig + ): T + + fun visitExternalProxyConfig(externalProxyConfig: ExternalProxyConfig): T + + /** + * Maps an unknown variant of [UnnamedSchemaWithArrayParent0] to a value of type + * [T]. + * + * An instance of [UnnamedSchemaWithArrayParent0] can contain an unknown variant + * if it was deserialized from data that doesn't match any known variant. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new variants that the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException( + "Unknown UnnamedSchemaWithArrayParent0: $json" + ) + } + } + + internal class Deserializer : + BaseDeserializer( + UnnamedSchemaWithArrayParent0::class + ) { + + override fun ObjectCodec.deserialize( + node: JsonNode + ): UnnamedSchemaWithArrayParent0 { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { + UnnamedSchemaWithArrayParent0( + browserbaseProxyConfig = it, + _json = json, + ) + }, + tryDeserialize(node, jacksonTypeRef()) + ?.let { + UnnamedSchemaWithArrayParent0( + externalProxyConfig = it, + _json = json, + ) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely + // incompatible with all the possible variants (e.g. deserializing from + // boolean). + 0 -> UnnamedSchemaWithArrayParent0(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use + // the first completely valid match, or simply the first match if none + // are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer( + UnnamedSchemaWithArrayParent0::class + ) { + + override fun serialize( + value: UnnamedSchemaWithArrayParent0, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.browserbaseProxyConfig != null -> + generator.writeObject(value.browserbaseProxyConfig) + value.externalProxyConfig != null -> + generator.writeObject(value.externalProxyConfig) + value._json != null -> generator.writeObject(value._json) + else -> + throw IllegalStateException("Invalid UnnamedSchemaWithArrayParent0") + } + } + } + + class BrowserbaseProxyConfig + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val type: JsonField, + private val domainPattern: JsonField, + private val geolocation: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("domainPattern") + @ExcludeMissing + domainPattern: JsonField = JsonMissing.of(), + @JsonProperty("geolocation") + @ExcludeMissing + geolocation: JsonField = JsonMissing.of(), + ) : this(type, domainPattern, geolocation, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun type(): Type = type.getRequired("type") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun domainPattern(): Optional = + domainPattern.getOptional("domainPattern") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun geolocation(): Optional = + geolocation.getOptional("geolocation") + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [domainPattern]. + * + * Unlike [domainPattern], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("domainPattern") + @ExcludeMissing + fun _domainPattern(): JsonField = domainPattern + + /** + * Returns the raw JSON value of [geolocation]. + * + * Unlike [geolocation], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("geolocation") + @ExcludeMissing + fun _geolocation(): JsonField = geolocation + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BrowserbaseProxyConfig]. + * + * The following fields are required: + * ```java + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BrowserbaseProxyConfig]. */ + class Builder internal constructor() { + + private var type: JsonField? = null + private var domainPattern: JsonField = JsonMissing.of() + private var geolocation: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(browserbaseProxyConfig: BrowserbaseProxyConfig) = apply { + type = browserbaseProxyConfig.type + domainPattern = browserbaseProxyConfig.domainPattern + geolocation = browserbaseProxyConfig.geolocation + additionalProperties = + browserbaseProxyConfig.additionalProperties.toMutableMap() + } + + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun domainPattern(domainPattern: String) = + domainPattern(JsonField.of(domainPattern)) + + /** + * Sets [Builder.domainPattern] to an arbitrary JSON value. + * + * You should usually call [Builder.domainPattern] with a well-typed + * [String] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun domainPattern(domainPattern: JsonField) = apply { + this.domainPattern = domainPattern + } + + fun geolocation(geolocation: Geolocation) = + geolocation(JsonField.of(geolocation)) + + /** + * Sets [Builder.geolocation] to an arbitrary JSON value. + * + * You should usually call [Builder.geolocation] with a well-typed + * [Geolocation] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun geolocation(geolocation: JsonField) = apply { + this.geolocation = geolocation + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BrowserbaseProxyConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BrowserbaseProxyConfig = + BrowserbaseProxyConfig( + checkRequired("type", type), + domainPattern, + geolocation, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BrowserbaseProxyConfig = apply { + if (validated) { + return@apply + } + + type().validate() + domainPattern() + geolocation().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (domainPattern.asKnown().isPresent) 1 else 0) + + (geolocation.asKnown().getOrNull()?.validity() ?: 0) + + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known member, and you want to know that value. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val BROWSERBASE = of("browserbase") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + BROWSERBASE + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For + * example, if the SDK is on an older version than the API, then the API + * may respond with new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + BROWSERBASE, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + BROWSERBASE -> Value.BROWSERBASE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + BROWSERBASE -> Known.BROWSERBASE + else -> throw StagehandInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class Geolocation + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val country: JsonField, + private val city: JsonField, + private val state: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("country") + @ExcludeMissing + country: JsonField = JsonMissing.of(), + @JsonProperty("city") + @ExcludeMissing + city: JsonField = JsonMissing.of(), + @JsonProperty("state") + @ExcludeMissing + state: JsonField = JsonMissing.of(), + ) : this(country, city, state, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded + * with an unexpected value). + */ + fun country(): String = country.getRequired("country") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun city(): Optional = city.getOptional("city") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun state(): Optional = state.getOptional("state") + + /** + * Returns the raw JSON value of [country]. + * + * Unlike [country], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("country") + @ExcludeMissing + fun _country(): JsonField = country + + /** + * Returns the raw JSON value of [city]. + * + * Unlike [city], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("city") @ExcludeMissing fun _city(): JsonField = city + + /** + * Returns the raw JSON value of [state]. + * + * Unlike [state], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("state") + @ExcludeMissing + fun _state(): JsonField = state + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [Geolocation]. + * + * The following fields are required: + * ```java + * .country() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Geolocation]. */ + class Builder internal constructor() { + + private var country: JsonField? = null + private var city: JsonField = JsonMissing.of() + private var state: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(geolocation: Geolocation) = apply { + country = geolocation.country + city = geolocation.city + state = geolocation.state + additionalProperties = + geolocation.additionalProperties.toMutableMap() + } + + fun country(country: String) = country(JsonField.of(country)) + + /** + * Sets [Builder.country] to an arbitrary JSON value. + * + * You should usually call [Builder.country] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun country(country: JsonField) = apply { + this.country = country + } + + fun city(city: String) = city(JsonField.of(city)) + + /** + * Sets [Builder.city] to an arbitrary JSON value. + * + * You should usually call [Builder.city] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun city(city: JsonField) = apply { this.city = city } + + fun state(state: String) = state(JsonField.of(state)) + + /** + * Sets [Builder.state] to an arbitrary JSON value. + * + * You should usually call [Builder.state] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun state(state: JsonField) = apply { this.state = state } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Geolocation]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + * + * The following fields are required: + * ```java + * .country() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Geolocation = + Geolocation( + checkRequired("country", country), + city, + state, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Geolocation = apply { + if (validated) { + return@apply + } + + country() + city() + state() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (country.asKnown().isPresent) 1 else 0) + + (if (city.asKnown().isPresent) 1 else 0) + + (if (state.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Geolocation && + country == other.country && + city == other.city && + state == other.state && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(country, city, state, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Geolocation{country=$country, city=$city, state=$state, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BrowserbaseProxyConfig && + type == other.type && + domainPattern == other.domainPattern && + geolocation == other.geolocation && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(type, domainPattern, geolocation, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BrowserbaseProxyConfig{type=$type, domainPattern=$domainPattern, geolocation=$geolocation, additionalProperties=$additionalProperties}" + } + + class ExternalProxyConfig + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val server: JsonField, + private val type: JsonField, + private val domainPattern: JsonField, + private val password: JsonField, + private val username: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("server") + @ExcludeMissing + server: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("domainPattern") + @ExcludeMissing + domainPattern: JsonField = JsonMissing.of(), + @JsonProperty("password") + @ExcludeMissing + password: JsonField = JsonMissing.of(), + @JsonProperty("username") + @ExcludeMissing + username: JsonField = JsonMissing.of(), + ) : this(server, type, domainPattern, password, username, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun server(): String = server.getRequired("server") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun type(): Type = type.getRequired("type") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun domainPattern(): Optional = + domainPattern.getOptional("domainPattern") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun password(): Optional = password.getOptional("password") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun username(): Optional = username.getOptional("username") + + /** + * Returns the raw JSON value of [server]. + * + * Unlike [server], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("server") + @ExcludeMissing + fun _server(): JsonField = server + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [domainPattern]. + * + * Unlike [domainPattern], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("domainPattern") + @ExcludeMissing + fun _domainPattern(): JsonField = domainPattern + + /** + * Returns the raw JSON value of [password]. + * + * Unlike [password], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("password") + @ExcludeMissing + fun _password(): JsonField = password + + /** + * Returns the raw JSON value of [username]. + * + * Unlike [username], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("username") + @ExcludeMissing + fun _username(): JsonField = username + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [ExternalProxyConfig]. + * + * The following fields are required: + * ```java + * .server() + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ExternalProxyConfig]. */ + class Builder internal constructor() { + + private var server: JsonField? = null + private var type: JsonField? = null + private var domainPattern: JsonField = JsonMissing.of() + private var password: JsonField = JsonMissing.of() + private var username: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(externalProxyConfig: ExternalProxyConfig) = apply { + server = externalProxyConfig.server + type = externalProxyConfig.type + domainPattern = externalProxyConfig.domainPattern + password = externalProxyConfig.password + username = externalProxyConfig.username + additionalProperties = + externalProxyConfig.additionalProperties.toMutableMap() + } + + fun server(server: String) = server(JsonField.of(server)) + + /** + * Sets [Builder.server] to an arbitrary JSON value. + * + * You should usually call [Builder.server] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun server(server: JsonField) = apply { this.server = server } + + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun domainPattern(domainPattern: String) = + domainPattern(JsonField.of(domainPattern)) + + /** + * Sets [Builder.domainPattern] to an arbitrary JSON value. + * + * You should usually call [Builder.domainPattern] with a well-typed + * [String] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun domainPattern(domainPattern: JsonField) = apply { + this.domainPattern = domainPattern + } + + fun password(password: String) = password(JsonField.of(password)) + + /** + * Sets [Builder.password] to an arbitrary JSON value. + * + * You should usually call [Builder.password] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun password(password: JsonField) = apply { + this.password = password + } + + fun username(username: String) = username(JsonField.of(username)) + + /** + * Sets [Builder.username] to an arbitrary JSON value. + * + * You should usually call [Builder.username] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun username(username: JsonField) = apply { + this.username = username + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ExternalProxyConfig]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .server() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ExternalProxyConfig = + ExternalProxyConfig( + checkRequired("server", server), + checkRequired("type", type), + domainPattern, + password, + username, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ExternalProxyConfig = apply { + if (validated) { + return@apply + } + + server() + type().validate() + domainPattern() + password() + username() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (server.asKnown().isPresent) 1 else 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + (if (domainPattern.asKnown().isPresent) 1 else 0) + + (if (password.asKnown().isPresent) 1 else 0) + + (if (username.asKnown().isPresent) 1 else 0) + + class Type + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data + * that doesn't match any known member, and you want to know that value. For + * example, if the SDK is on an older version than the API, then the API may + * respond with new members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue + fun _value(): JsonField = value + + companion object { + + @JvmField val EXTERNAL = of("external") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + EXTERNAL + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] + * member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For + * example, if the SDK is on an older version than the API, then the API + * may respond with new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + EXTERNAL, + /** + * An enum member indicating that [Type] was instantiated with an + * unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always + * known or if you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + EXTERNAL -> Value.EXTERNAL + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always + * known and don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + EXTERNAL -> Known.EXTERNAL + else -> throw StagehandInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily + * for debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExternalProxyConfig && + server == other.server && + type == other.type && + domainPattern == other.domainPattern && + password == other.password && + username == other.username && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + server, + type, + domainPattern, + password, + username, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ExternalProxyConfig{server=$server, type=$type, domainPattern=$domainPattern, password=$password, username=$username, additionalProperties=$additionalProperties}" + } + } + } + + class Region @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val US_WEST_2 = of("us-west-2") + + @JvmField val US_EAST_1 = of("us-east-1") + + @JvmField val EU_CENTRAL_1 = of("eu-central-1") + + @JvmField val AP_SOUTHEAST_1 = of("ap-southeast-1") + + @JvmStatic fun of(value: String) = Region(JsonField.of(value)) + } + + /** An enum containing [Region]'s known values. */ + enum class Known { + US_WEST_2, + US_EAST_1, + EU_CENTRAL_1, + AP_SOUTHEAST_1, + } + + /** + * An enum containing [Region]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Region] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + US_WEST_2, + US_EAST_1, + EU_CENTRAL_1, + AP_SOUTHEAST_1, + /** + * An enum member indicating that [Region] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + US_WEST_2 -> Value.US_WEST_2 + US_EAST_1 -> Value.US_EAST_1 + EU_CENTRAL_1 -> Value.EU_CENTRAL_1 + AP_SOUTHEAST_1 -> Value.AP_SOUTHEAST_1 + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + US_WEST_2 -> Known.US_WEST_2 + US_EAST_1 -> Known.US_EAST_1 + EU_CENTRAL_1 -> Known.EU_CENTRAL_1 + AP_SOUTHEAST_1 -> Known.AP_SOUTHEAST_1 + else -> throw StagehandInvalidDataException("Unknown Region: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Region = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Region && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + class UserMetadata + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [UserMetadata]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [UserMetadata]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(userMetadata: UserMetadata) = apply { + additionalProperties = userMetadata.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [UserMetadata]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): UserMetadata = UserMetadata(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): UserMetadata = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is UserMetadata && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "UserMetadata{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BrowserbaseSessionCreateParams && + browserSettings == other.browserSettings && + extensionId == other.extensionId && + keepAlive == other.keepAlive && + projectId == other.projectId && + proxies == other.proxies && + region == other.region && + timeout == other.timeout && + userMetadata == other.userMetadata && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + browserSettings, + extensionId, + keepAlive, + projectId, + proxies, + region, + timeout, + userMetadata, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" + } + + /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ + class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val _0 = of(0.0) + + @JvmField val _1 = of(1.0) + + @JvmField val _2 = of(2.0) + + @JvmStatic fun of(value: Double) = Verbose(JsonField.of(value)) + } + + /** An enum containing [Verbose]'s known values. */ + enum class Known { + _0, + _1, + _2, + } + + /** + * An enum containing [Verbose]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Verbose] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + _0, + _1, + _2, + /** An enum member indicating that [Verbose] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + _0 -> Value._0 + _1 -> Value._1 + _2 -> Value._2 + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + _0 -> Known._0 + _1 -> Known._1 + _2 -> Known._2 + else -> throw StagehandInvalidDataException("Unknown Verbose: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asDouble(): Double = + _value().asNumber().getOrNull()?.toDouble() + ?: throw StagehandInvalidDataException("Value is not a Double") + + private var validated: Boolean = false + + fun validate(): Verbose = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Verbose && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Client SDK language */ + class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TYPESCRIPT = of("typescript") + + @JvmField val PYTHON = of("python") + + @JvmField val PLAYGROUND = of("playground") + + @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) + } + + /** An enum containing [XLanguage]'s known values. */ + enum class Known { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + } + + /** + * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XLanguage] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TYPESCRIPT, + PYTHON, + PLAYGROUND, + /** + * An enum member indicating that [XLanguage] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TYPESCRIPT -> Value.TYPESCRIPT + PYTHON -> Value.PYTHON + PLAYGROUND -> Value.PLAYGROUND + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TYPESCRIPT -> Known.TYPESCRIPT + PYTHON -> Known.PYTHON + PLAYGROUND -> Known.PLAYGROUND + else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XLanguage = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XLanguage && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index b63f41e..420925f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -2,20 +2,60 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import kotlin.jvm.optionals.getOrNull class SessionStartResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Success = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -31,20 +71,52 @@ private constructor(private val additionalProperties: MutableMap? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionStartResponse: SessionStartResponse) = apply { + data = sessionStartResponse.data + success = sessionStartResponse.success additionalProperties = sessionStartResponse.additionalProperties.toMutableMap() } + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + fun success(success: Success) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -68,9 +140,21 @@ private constructor(private val additionalProperties: MutableMap, + private val sessionId: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("available") + @ExcludeMissing + available: JsonField = JsonMissing.of(), + @JsonProperty("sessionId") + @ExcludeMissing + sessionId: JsonField = JsonMissing.of(), + ) : this(available, sessionId, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun available(): Boolean = available.getRequired("available") + + /** + * Unique session identifier + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun sessionId(): String = sessionId.getRequired("sessionId") + + /** + * Returns the raw JSON value of [available]. + * + * Unlike [available], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("available") @ExcludeMissing fun _available(): JsonField = available + + /** + * Returns the raw JSON value of [sessionId]. + * + * Unlike [sessionId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sessionId") @ExcludeMissing fun _sessionId(): JsonField = sessionId + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .available() + * .sessionId() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var available: JsonField? = null + private var sessionId: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + available = data.available + sessionId = data.sessionId + additionalProperties = data.additionalProperties.toMutableMap() + } + + fun available(available: Boolean) = available(JsonField.of(available)) + + /** + * Sets [Builder.available] to an arbitrary JSON value. + * + * You should usually call [Builder.available] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun available(available: JsonField) = apply { this.available = available } + + /** Unique session identifier */ + fun sessionId(sessionId: String) = sessionId(JsonField.of(sessionId)) + + /** + * Sets [Builder.sessionId] to an arbitrary JSON value. + * + * You should usually call [Builder.sessionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sessionId(sessionId: JsonField) = apply { this.sessionId = sessionId } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .available() + * .sessionId() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Data = + Data( + checkRequired("available", available), + checkRequired("sessionId", sessionId), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + available() + sessionId() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (available.asKnown().isPresent) 1 else 0) + + (if (sessionId.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + available == other.available && + sessionId == other.sessionId && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(available, sessionId, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Data{available=$available, sessionId=$sessionId, additionalProperties=$additionalProperties}" + } + + class Success @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of(true) + + @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) + } + + /** An enum containing [Success]'s known values. */ + enum class Known { + TRUE + } + + /** + * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Success] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + /** An enum member indicating that [Success] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + else -> throw StagehandInvalidDataException("Unknown Success: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asBoolean(): Boolean = + _value().asBoolean().orElseThrow { + StagehandInvalidDataException("Value is not a Boolean") + } + + private var validated: Boolean = false + + fun validate(): Success = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Success && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is SessionStartResponse && additionalProperties == other.additionalProperties + return other is SessionStartResponse && + data == other.data && + success == other.success && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(data, success, additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "SessionStartResponse{additionalProperties=$additionalProperties}" + override fun toString() = + "SessionStartResponse{data=$data, success=$success, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index 435bf27..423fd57 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -3,15 +3,14 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse import com.browserbase.api.models.sessions.SessionEndParams import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExecuteParams +import com.browserbase.api.models.sessions.SessionExecuteResponse import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionExtractResponse import com.browserbase.api.models.sessions.SessionNavigateParams @@ -40,21 +39,20 @@ interface SessionServiceAsync { /** * Executes a browser action using natural language instructions or a predefined Action object. */ - fun act(id: JsonValue): CompletableFuture = act(id, SessionActParams.none()) + fun act(id: String, params: SessionActParams): CompletableFuture = + act(id, params, RequestOptions.none()) /** @see act */ fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), + id: String, + params: SessionActParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture = act(params.toBuilder().id(id).build(), requestOptions) /** @see act */ - fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), - ): CompletableFuture = act(id, params, RequestOptions.none()) + fun act(params: SessionActParams): CompletableFuture = + act(params, RequestOptions.none()) /** @see act */ fun act( @@ -62,20 +60,12 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture - /** @see act */ - fun act(params: SessionActParams): CompletableFuture = - act(params, RequestOptions.none()) - - /** @see act */ - fun act(id: JsonValue, requestOptions: RequestOptions): CompletableFuture = - act(id, SessionActParams.none(), requestOptions) - /** Terminates the browser session and releases all associated resources. */ - fun end(id: JsonValue): CompletableFuture = end(id, SessionEndParams.none()) + fun end(id: String): CompletableFuture = end(id, SessionEndParams.none()) /** @see end */ fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture = @@ -83,7 +73,7 @@ interface SessionServiceAsync { /** @see end */ fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), ): CompletableFuture = end(id, params, RequestOptions.none()) @@ -98,53 +88,40 @@ interface SessionServiceAsync { end(params, RequestOptions.none()) /** @see end */ - fun end(id: JsonValue, requestOptions: RequestOptions): CompletableFuture = + fun end(id: String, requestOptions: RequestOptions): CompletableFuture = end(id, SessionEndParams.none(), requestOptions) /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ - fun executeAgent(id: JsonValue): CompletableFuture = - executeAgent(id, SessionExecuteAgentParams.none()) - - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + fun execute( + id: String, + params: SessionExecuteParams, + ): CompletableFuture = execute(id, params, RequestOptions.none()) + + /** @see execute */ + fun execute( + id: String, + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - executeAgent(params.toBuilder().id(id).build(), requestOptions) - - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), - ): CompletableFuture = - executeAgent(id, params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture = + execute(params.toBuilder().id(id).build(), requestOptions) - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams - ): CompletableFuture = executeAgent(params, RequestOptions.none()) + /** @see execute */ + fun execute(params: SessionExecuteParams): CompletableFuture = + execute(params, RequestOptions.none()) - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - requestOptions: RequestOptions, - ): CompletableFuture = - executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + /** @see execute */ + fun execute( + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture /** Extracts structured data from the current page using AI-powered analysis. */ - fun extract(id: JsonValue): CompletableFuture = + fun extract(id: String): CompletableFuture = extract(id, SessionExtractParams.none()) /** @see extract */ fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture = @@ -152,7 +129,7 @@ interface SessionServiceAsync { /** @see extract */ fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), ): CompletableFuture = extract(id, params, RequestOptions.none()) @@ -168,34 +145,24 @@ interface SessionServiceAsync { /** @see extract */ fun extract( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): CompletableFuture = extract(id, SessionExtractParams.none(), requestOptions) /** Navigates the browser to the specified URL. */ - fun navigate(id: JsonValue): CompletableFuture = - navigate(id, SessionNavigateParams.none()) - - /** @see navigate */ - fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = - navigate(params.toBuilder().id(id).build(), requestOptions) - - /** @see navigate */ fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), + id: String, + params: SessionNavigateParams, ): CompletableFuture = navigate(id, params, RequestOptions.none()) /** @see navigate */ fun navigate( + id: String, params: SessionNavigateParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture = + navigate(params.toBuilder().id(id).build(), requestOptions) /** @see navigate */ fun navigate(params: SessionNavigateParams): CompletableFuture = @@ -203,21 +170,20 @@ interface SessionServiceAsync { /** @see navigate */ fun navigate( - id: JsonValue, - requestOptions: RequestOptions, - ): CompletableFuture = - navigate(id, SessionNavigateParams.none(), requestOptions) + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture /** * Identifies and returns available actions on the current page that match the given * instruction. */ - fun observe(id: JsonValue): CompletableFuture = + fun observe(id: String): CompletableFuture = observe(id, SessionObserveParams.none()) /** @see observe */ fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture = @@ -225,7 +191,7 @@ interface SessionServiceAsync { /** @see observe */ fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), ): CompletableFuture = observe(id, params, RequestOptions.none()) @@ -241,7 +207,7 @@ interface SessionServiceAsync { /** @see observe */ fun observe( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): CompletableFuture = observe(id, SessionObserveParams.none(), requestOptions) @@ -250,23 +216,15 @@ interface SessionServiceAsync { * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. */ - fun start(): CompletableFuture = start(SessionStartParams.none()) + fun start(params: SessionStartParams): CompletableFuture = + start(params, RequestOptions.none()) /** @see start */ fun start( - params: SessionStartParams = SessionStartParams.none(), + params: SessionStartParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture - /** @see start */ - fun start( - params: SessionStartParams = SessionStartParams.none() - ): CompletableFuture = start(params, RequestOptions.none()) - - /** @see start */ - fun start(requestOptions: RequestOptions): CompletableFuture = - start(SessionStartParams.none(), requestOptions) - /** * A view of [SessionServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -282,32 +240,22 @@ interface SessionServiceAsync { ): SessionServiceAsync.WithRawResponse /** - * Returns a raw HTTP response for `post /sessions/{id}/act`, but is otherwise the same as - * [SessionServiceAsync.act]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/act`, but is otherwise the same + * as [SessionServiceAsync.act]. */ - fun act(id: JsonValue): CompletableFuture> = - act(id, SessionActParams.none()) - - /** @see act */ fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - act(params.toBuilder().id(id).build(), requestOptions) - - /** @see act */ - fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), + id: String, + params: SessionActParams, ): CompletableFuture> = act(id, params, RequestOptions.none()) /** @see act */ fun act( + id: String, params: SessionActParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> = + act(params.toBuilder().id(id).build(), requestOptions) /** @see act */ fun act(params: SessionActParams): CompletableFuture> = @@ -315,21 +263,20 @@ interface SessionServiceAsync { /** @see act */ fun act( - id: JsonValue, - requestOptions: RequestOptions, - ): CompletableFuture> = - act(id, SessionActParams.none(), requestOptions) + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> /** - * Returns a raw HTTP response for `post /sessions/{id}/end`, but is otherwise the same as - * [SessionServiceAsync.end]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/end`, but is otherwise the same + * as [SessionServiceAsync.end]. */ - fun end(id: JsonValue): CompletableFuture> = + fun end(id: String): CompletableFuture> = end(id, SessionEndParams.none()) /** @see end */ fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = @@ -337,7 +284,7 @@ interface SessionServiceAsync { /** @see end */ fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), ): CompletableFuture> = end(id, params, RequestOptions.none()) @@ -354,64 +301,51 @@ interface SessionServiceAsync { /** @see end */ fun end( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): CompletableFuture> = end(id, SessionEndParams.none(), requestOptions) /** - * Returns a raw HTTP response for `post /sessions/{id}/agentExecute`, but is otherwise the - * same as [SessionServiceAsync.executeAgent]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise + * the same as [SessionServiceAsync.execute]. */ - fun executeAgent( - id: JsonValue - ): CompletableFuture> = - executeAgent(id, SessionExecuteAgentParams.none()) - - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + fun execute( + id: String, + params: SessionExecuteParams, + ): CompletableFuture> = + execute(id, params, RequestOptions.none()) + + /** @see execute */ + fun execute( + id: String, + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - executeAgent(params.toBuilder().id(id).build(), requestOptions) - - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), - ): CompletableFuture> = - executeAgent(id, params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams, + ): CompletableFuture> = + execute(params.toBuilder().id(id).build(), requestOptions) + + /** @see execute */ + fun execute( + params: SessionExecuteParams + ): CompletableFuture> = + execute(params, RequestOptions.none()) + + /** @see execute */ + fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams - ): CompletableFuture> = - executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - requestOptions: RequestOptions, - ): CompletableFuture> = - executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + ): CompletableFuture> /** - * Returns a raw HTTP response for `post /sessions/{id}/extract`, but is otherwise the same - * as [SessionServiceAsync.extract]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/extract`, but is otherwise the + * same as [SessionServiceAsync.extract]. */ - fun extract(id: JsonValue): CompletableFuture> = + fun extract(id: String): CompletableFuture> = extract(id, SessionExtractParams.none()) /** @see extract */ fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = @@ -419,7 +353,7 @@ interface SessionServiceAsync { /** @see extract */ fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), ): CompletableFuture> = extract(id, params, RequestOptions.none()) @@ -438,38 +372,28 @@ interface SessionServiceAsync { /** @see extract */ fun extract( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): CompletableFuture> = extract(id, SessionExtractParams.none(), requestOptions) /** - * Returns a raw HTTP response for `post /sessions/{id}/navigate`, but is otherwise the same - * as [SessionServiceAsync.navigate]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/navigate`, but is otherwise the + * same as [SessionServiceAsync.navigate]. */ - fun navigate(id: JsonValue): CompletableFuture> = - navigate(id, SessionNavigateParams.none()) - - /** @see navigate */ fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - navigate(params.toBuilder().id(id).build(), requestOptions) - - /** @see navigate */ - fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), + id: String, + params: SessionNavigateParams, ): CompletableFuture> = navigate(id, params, RequestOptions.none()) /** @see navigate */ fun navigate( + id: String, params: SessionNavigateParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> = + navigate(params.toBuilder().id(id).build(), requestOptions) /** @see navigate */ fun navigate( @@ -479,21 +403,20 @@ interface SessionServiceAsync { /** @see navigate */ fun navigate( - id: JsonValue, - requestOptions: RequestOptions, - ): CompletableFuture> = - navigate(id, SessionNavigateParams.none(), requestOptions) + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> /** - * Returns a raw HTTP response for `post /sessions/{id}/observe`, but is otherwise the same - * as [SessionServiceAsync.observe]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/observe`, but is otherwise the + * same as [SessionServiceAsync.observe]. */ - fun observe(id: JsonValue): CompletableFuture> = + fun observe(id: String): CompletableFuture> = observe(id, SessionObserveParams.none()) /** @see observe */ fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = @@ -501,7 +424,7 @@ interface SessionServiceAsync { /** @see observe */ fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), ): CompletableFuture> = observe(id, params, RequestOptions.none()) @@ -520,34 +443,24 @@ interface SessionServiceAsync { /** @see observe */ fun observe( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): CompletableFuture> = observe(id, SessionObserveParams.none(), requestOptions) /** - * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as + * Returns a raw HTTP response for `post /v1/sessions/start`, but is otherwise the same as * [SessionServiceAsync.start]. */ - fun start(): CompletableFuture> = - start(SessionStartParams.none()) - - /** @see start */ - fun start( - params: SessionStartParams = SessionStartParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> - - /** @see start */ fun start( - params: SessionStartParams = SessionStartParams.none() + params: SessionStartParams ): CompletableFuture> = start(params, RequestOptions.none()) /** @see start */ fun start( - requestOptions: RequestOptions - ): CompletableFuture> = - start(SessionStartParams.none(), requestOptions) + params: SessionStartParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 7746896..99037bc 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.checkRequired import com.browserbase.api.core.handlers.errorBodyHandler import com.browserbase.api.core.handlers.errorHandler import com.browserbase.api.core.handlers.jsonHandler @@ -19,8 +20,8 @@ import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse import com.browserbase.api.models.sessions.SessionEndParams import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExecuteParams +import com.browserbase.api.models.sessions.SessionExecuteResponse import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionExtractResponse import com.browserbase.api.models.sessions.SessionNavigateParams @@ -31,6 +32,7 @@ import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import java.util.concurrent.CompletableFuture import java.util.function.Consumer +import kotlin.jvm.optionals.getOrNull class SessionServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : SessionServiceAsync { @@ -48,49 +50,49 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl params: SessionActParams, requestOptions: RequestOptions, ): CompletableFuture = - // post /sessions/{id}/act + // post /v1/sessions/{id}/act withRawResponse().act(params, requestOptions).thenApply { it.parse() } override fun end( params: SessionEndParams, requestOptions: RequestOptions, ): CompletableFuture = - // post /sessions/{id}/end + // post /v1/sessions/{id}/end withRawResponse().end(params, requestOptions).thenApply { it.parse() } - override fun executeAgent( - params: SessionExecuteAgentParams, + override fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions, - ): CompletableFuture = - // post /sessions/{id}/agentExecute - withRawResponse().executeAgent(params, requestOptions).thenApply { it.parse() } + ): CompletableFuture = + // post /v1/sessions/{id}/agentExecute + withRawResponse().execute(params, requestOptions).thenApply { it.parse() } override fun extract( params: SessionExtractParams, requestOptions: RequestOptions, ): CompletableFuture = - // post /sessions/{id}/extract + // post /v1/sessions/{id}/extract withRawResponse().extract(params, requestOptions).thenApply { it.parse() } override fun navigate( params: SessionNavigateParams, requestOptions: RequestOptions, ): CompletableFuture = - // post /sessions/{id}/navigate + // post /v1/sessions/{id}/navigate withRawResponse().navigate(params, requestOptions).thenApply { it.parse() } override fun observe( params: SessionObserveParams, requestOptions: RequestOptions, ): CompletableFuture = - // post /sessions/{id}/observe + // post /v1/sessions/{id}/observe withRawResponse().observe(params, requestOptions).thenApply { it.parse() } override fun start( params: SessionStartParams, requestOptions: RequestOptions, ): CompletableFuture = - // post /sessions/start + // post /v1/sessions/start withRawResponse().start(params, requestOptions).thenApply { it.parse() } class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -113,11 +115,14 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl params: SessionActParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "act") + .addPathSegments("v1", "sessions", params._pathParam(0), "act") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) @@ -144,11 +149,14 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl params: SessionEndParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "end") + .addPathSegments("v1", "sessions", params._pathParam(0), "end") .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } .build() .prepareAsync(clientOptions, params) @@ -168,18 +176,21 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl } } - private val executeAgentHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val executeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - override fun executeAgent( - params: SessionExecuteAgentParams, + override fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "agentExecute") + .addPathSegments("v1", "sessions", params._pathParam(0), "agentExecute") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) @@ -189,7 +200,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .thenApply { response -> errorHandler.handle(response).parseable { response - .use { executeAgentHandler.handle(it) } + .use { executeHandler.handle(it) } .also { if (requestOptions.responseValidation!!) { it.validate() @@ -206,11 +217,14 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl params: SessionExtractParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "extract") + .addPathSegments("v1", "sessions", params._pathParam(0), "extract") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) @@ -237,11 +251,14 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl params: SessionNavigateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "navigate") + .addPathSegments("v1", "sessions", params._pathParam(0), "navigate") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) @@ -268,11 +285,14 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl params: SessionObserveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "observe") + .addPathSegments("v1", "sessions", params._pathParam(0), "observe") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) @@ -303,7 +323,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", "start") + .addPathSegments("v1", "sessions", "start") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index f29cc14..df7bb72 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -3,15 +3,14 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse import com.browserbase.api.models.sessions.SessionEndParams import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExecuteParams +import com.browserbase.api.models.sessions.SessionExecuteResponse import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionExtractResponse import com.browserbase.api.models.sessions.SessionNavigateParams @@ -40,18 +39,18 @@ interface SessionService { /** * Executes a browser action using natural language instructions or a predefined Action object. */ - fun act(id: JsonValue): SessionActResponse = act(id, SessionActParams.none()) + fun act(id: String, params: SessionActParams): SessionActResponse = + act(id, params, RequestOptions.none()) /** @see act */ fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), + id: String, + params: SessionActParams, requestOptions: RequestOptions = RequestOptions.none(), ): SessionActResponse = act(params.toBuilder().id(id).build(), requestOptions) /** @see act */ - fun act(id: JsonValue, params: SessionActParams = SessionActParams.none()): SessionActResponse = - act(id, params, RequestOptions.none()) + fun act(params: SessionActParams): SessionActResponse = act(params, RequestOptions.none()) /** @see act */ fun act( @@ -59,25 +58,18 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): SessionActResponse - /** @see act */ - fun act(params: SessionActParams): SessionActResponse = act(params, RequestOptions.none()) - - /** @see act */ - fun act(id: JsonValue, requestOptions: RequestOptions): SessionActResponse = - act(id, SessionActParams.none(), requestOptions) - /** Terminates the browser session and releases all associated resources. */ - fun end(id: JsonValue): SessionEndResponse = end(id, SessionEndParams.none()) + fun end(id: String): SessionEndResponse = end(id, SessionEndParams.none()) /** @see end */ fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): SessionEndResponse = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ - fun end(id: JsonValue, params: SessionEndParams = SessionEndParams.none()): SessionEndResponse = + fun end(id: String, params: SessionEndParams = SessionEndParams.none()): SessionEndResponse = end(id, params, RequestOptions.none()) /** @see end */ @@ -90,53 +82,43 @@ interface SessionService { fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) /** @see end */ - fun end(id: JsonValue, requestOptions: RequestOptions): SessionEndResponse = + fun end(id: String, requestOptions: RequestOptions): SessionEndResponse = end(id, SessionEndParams.none(), requestOptions) /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ - fun executeAgent(id: JsonValue): SessionExecuteAgentResponse = - executeAgent(id, SessionExecuteAgentParams.none()) + fun execute(id: String, params: SessionExecuteParams): SessionExecuteResponse = + execute(id, params, RequestOptions.none()) - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + /** @see execute */ + fun execute( + id: String, + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): SessionExecuteAgentResponse = executeAgent(params.toBuilder().id(id).build(), requestOptions) + ): SessionExecuteResponse = execute(params.toBuilder().id(id).build(), requestOptions) - /** @see executeAgent */ - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), - ): SessionExecuteAgentResponse = executeAgent(id, params, RequestOptions.none()) + /** @see execute */ + fun execute(params: SessionExecuteParams): SessionExecuteResponse = + execute(params, RequestOptions.none()) - /** @see executeAgent */ - fun executeAgent( - params: SessionExecuteAgentParams, + /** @see execute */ + fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): SessionExecuteAgentResponse - - /** @see executeAgent */ - fun executeAgent(params: SessionExecuteAgentParams): SessionExecuteAgentResponse = - executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - fun executeAgent(id: JsonValue, requestOptions: RequestOptions): SessionExecuteAgentResponse = - executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + ): SessionExecuteResponse /** Extracts structured data from the current page using AI-powered analysis. */ - fun extract(id: JsonValue): SessionExtractResponse = extract(id, SessionExtractParams.none()) + fun extract(id: String): SessionExtractResponse = extract(id, SessionExtractParams.none()) /** @see extract */ fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): SessionExtractResponse = extract(params.toBuilder().id(id).build(), requestOptions) /** @see extract */ fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), ): SessionExtractResponse = extract(id, params, RequestOptions.none()) @@ -151,25 +133,23 @@ interface SessionService { extract(params, RequestOptions.none()) /** @see extract */ - fun extract(id: JsonValue, requestOptions: RequestOptions): SessionExtractResponse = + fun extract(id: String, requestOptions: RequestOptions): SessionExtractResponse = extract(id, SessionExtractParams.none(), requestOptions) /** Navigates the browser to the specified URL. */ - fun navigate(id: JsonValue): SessionNavigateResponse = - navigate(id, SessionNavigateParams.none()) + fun navigate(id: String, params: SessionNavigateParams): SessionNavigateResponse = + navigate(id, params, RequestOptions.none()) /** @see navigate */ fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), + id: String, + params: SessionNavigateParams, requestOptions: RequestOptions = RequestOptions.none(), ): SessionNavigateResponse = navigate(params.toBuilder().id(id).build(), requestOptions) /** @see navigate */ - fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), - ): SessionNavigateResponse = navigate(id, params, RequestOptions.none()) + fun navigate(params: SessionNavigateParams): SessionNavigateResponse = + navigate(params, RequestOptions.none()) /** @see navigate */ fun navigate( @@ -177,30 +157,22 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): SessionNavigateResponse - /** @see navigate */ - fun navigate(params: SessionNavigateParams): SessionNavigateResponse = - navigate(params, RequestOptions.none()) - - /** @see navigate */ - fun navigate(id: JsonValue, requestOptions: RequestOptions): SessionNavigateResponse = - navigate(id, SessionNavigateParams.none(), requestOptions) - /** * Identifies and returns available actions on the current page that match the given * instruction. */ - fun observe(id: JsonValue): SessionObserveResponse = observe(id, SessionObserveParams.none()) + fun observe(id: String): SessionObserveResponse = observe(id, SessionObserveParams.none()) /** @see observe */ fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): SessionObserveResponse = observe(params.toBuilder().id(id).build(), requestOptions) /** @see observe */ fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), ): SessionObserveResponse = observe(id, params, RequestOptions.none()) @@ -215,29 +187,22 @@ interface SessionService { observe(params, RequestOptions.none()) /** @see observe */ - fun observe(id: JsonValue, requestOptions: RequestOptions): SessionObserveResponse = + fun observe(id: String, requestOptions: RequestOptions): SessionObserveResponse = observe(id, SessionObserveParams.none(), requestOptions) /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. */ - fun start(): SessionStartResponse = start(SessionStartParams.none()) + fun start(params: SessionStartParams): SessionStartResponse = + start(params, RequestOptions.none()) /** @see start */ fun start( - params: SessionStartParams = SessionStartParams.none(), + params: SessionStartParams, requestOptions: RequestOptions = RequestOptions.none(), ): SessionStartResponse - /** @see start */ - fun start(params: SessionStartParams = SessionStartParams.none()): SessionStartResponse = - start(params, RequestOptions.none()) - - /** @see start */ - fun start(requestOptions: RequestOptions): SessionStartResponse = - start(SessionStartParams.none(), requestOptions) - /** A view of [SessionService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -249,28 +214,26 @@ interface SessionService { fun withOptions(modifier: Consumer): SessionService.WithRawResponse /** - * Returns a raw HTTP response for `post /sessions/{id}/act`, but is otherwise the same as - * [SessionService.act]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/act`, but is otherwise the same + * as [SessionService.act]. */ @MustBeClosed - fun act(id: JsonValue): HttpResponseFor = - act(id, SessionActParams.none()) + fun act(id: String, params: SessionActParams): HttpResponseFor = + act(id, params, RequestOptions.none()) /** @see act */ @MustBeClosed fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), + id: String, + params: SessionActParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor = act(params.toBuilder().id(id).build(), requestOptions) /** @see act */ @MustBeClosed - fun act( - id: JsonValue, - params: SessionActParams = SessionActParams.none(), - ): HttpResponseFor = act(id, params, RequestOptions.none()) + fun act(params: SessionActParams): HttpResponseFor = + act(params, RequestOptions.none()) /** @see act */ @MustBeClosed @@ -279,30 +242,17 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor - /** @see act */ - @MustBeClosed - fun act(params: SessionActParams): HttpResponseFor = - act(params, RequestOptions.none()) - - /** @see act */ - @MustBeClosed - fun act( - id: JsonValue, - requestOptions: RequestOptions, - ): HttpResponseFor = act(id, SessionActParams.none(), requestOptions) - /** - * Returns a raw HTTP response for `post /sessions/{id}/end`, but is otherwise the same as - * [SessionService.end]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/end`, but is otherwise the same + * as [SessionService.end]. */ @MustBeClosed - fun end(id: JsonValue): HttpResponseFor = - end(id, SessionEndParams.none()) + fun end(id: String): HttpResponseFor = end(id, SessionEndParams.none()) /** @see end */ @MustBeClosed fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor = @@ -311,7 +261,7 @@ interface SessionService { /** @see end */ @MustBeClosed fun end( - id: JsonValue, + id: String, params: SessionEndParams = SessionEndParams.none(), ): HttpResponseFor = end(id, params, RequestOptions.none()) @@ -329,70 +279,52 @@ interface SessionService { /** @see end */ @MustBeClosed - fun end( - id: JsonValue, - requestOptions: RequestOptions, - ): HttpResponseFor = end(id, SessionEndParams.none(), requestOptions) + fun end(id: String, requestOptions: RequestOptions): HttpResponseFor = + end(id, SessionEndParams.none(), requestOptions) /** - * Returns a raw HTTP response for `post /sessions/{id}/agentExecute`, but is otherwise the - * same as [SessionService.executeAgent]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise + * the same as [SessionService.execute]. */ @MustBeClosed - fun executeAgent(id: JsonValue): HttpResponseFor = - executeAgent(id, SessionExecuteAgentParams.none()) + fun execute( + id: String, + params: SessionExecuteParams, + ): HttpResponseFor = execute(id, params, RequestOptions.none()) - /** @see executeAgent */ + /** @see execute */ @MustBeClosed - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), + fun execute( + id: String, + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - executeAgent(params.toBuilder().id(id).build(), requestOptions) + ): HttpResponseFor = + execute(params.toBuilder().id(id).build(), requestOptions) - /** @see executeAgent */ + /** @see execute */ @MustBeClosed - fun executeAgent( - id: JsonValue, - params: SessionExecuteAgentParams = SessionExecuteAgentParams.none(), - ): HttpResponseFor = - executeAgent(id, params, RequestOptions.none()) + fun execute(params: SessionExecuteParams): HttpResponseFor = + execute(params, RequestOptions.none()) - /** @see executeAgent */ + /** @see execute */ @MustBeClosed - fun executeAgent( - params: SessionExecuteAgentParams, + fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor - - /** @see executeAgent */ - @MustBeClosed - fun executeAgent( - params: SessionExecuteAgentParams - ): HttpResponseFor = - executeAgent(params, RequestOptions.none()) - - /** @see executeAgent */ - @MustBeClosed - fun executeAgent( - id: JsonValue, - requestOptions: RequestOptions, - ): HttpResponseFor = - executeAgent(id, SessionExecuteAgentParams.none(), requestOptions) + ): HttpResponseFor /** - * Returns a raw HTTP response for `post /sessions/{id}/extract`, but is otherwise the same - * as [SessionService.extract]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/extract`, but is otherwise the + * same as [SessionService.extract]. */ @MustBeClosed - fun extract(id: JsonValue): HttpResponseFor = + fun extract(id: String): HttpResponseFor = extract(id, SessionExtractParams.none()) /** @see extract */ @MustBeClosed fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor = @@ -401,7 +333,7 @@ interface SessionService { /** @see extract */ @MustBeClosed fun extract( - id: JsonValue, + id: String, params: SessionExtractParams = SessionExtractParams.none(), ): HttpResponseFor = extract(id, params, RequestOptions.none()) @@ -420,41 +352,29 @@ interface SessionService { /** @see extract */ @MustBeClosed fun extract( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): HttpResponseFor = extract(id, SessionExtractParams.none(), requestOptions) /** - * Returns a raw HTTP response for `post /sessions/{id}/navigate`, but is otherwise the same - * as [SessionService.navigate]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/navigate`, but is otherwise the + * same as [SessionService.navigate]. */ @MustBeClosed - fun navigate(id: JsonValue): HttpResponseFor = - navigate(id, SessionNavigateParams.none()) - - /** @see navigate */ - @MustBeClosed fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = - navigate(params.toBuilder().id(id).build(), requestOptions) - - /** @see navigate */ - @MustBeClosed - fun navigate( - id: JsonValue, - params: SessionNavigateParams = SessionNavigateParams.none(), + id: String, + params: SessionNavigateParams, ): HttpResponseFor = navigate(id, params, RequestOptions.none()) /** @see navigate */ @MustBeClosed fun navigate( + id: String, params: SessionNavigateParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponseFor = + navigate(params.toBuilder().id(id).build(), requestOptions) /** @see navigate */ @MustBeClosed @@ -464,23 +384,22 @@ interface SessionService { /** @see navigate */ @MustBeClosed fun navigate( - id: JsonValue, - requestOptions: RequestOptions, - ): HttpResponseFor = - navigate(id, SessionNavigateParams.none(), requestOptions) + params: SessionNavigateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor /** - * Returns a raw HTTP response for `post /sessions/{id}/observe`, but is otherwise the same - * as [SessionService.observe]. + * Returns a raw HTTP response for `post /v1/sessions/{id}/observe`, but is otherwise the + * same as [SessionService.observe]. */ @MustBeClosed - fun observe(id: JsonValue): HttpResponseFor = + fun observe(id: String): HttpResponseFor = observe(id, SessionObserveParams.none()) /** @see observe */ @MustBeClosed fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor = @@ -489,7 +408,7 @@ interface SessionService { /** @see observe */ @MustBeClosed fun observe( - id: JsonValue, + id: String, params: SessionObserveParams = SessionObserveParams.none(), ): HttpResponseFor = observe(id, params, RequestOptions.none()) @@ -508,34 +427,24 @@ interface SessionService { /** @see observe */ @MustBeClosed fun observe( - id: JsonValue, + id: String, requestOptions: RequestOptions, ): HttpResponseFor = observe(id, SessionObserveParams.none(), requestOptions) /** - * Returns a raw HTTP response for `post /sessions/start`, but is otherwise the same as + * Returns a raw HTTP response for `post /v1/sessions/start`, but is otherwise the same as * [SessionService.start]. */ @MustBeClosed - fun start(): HttpResponseFor = start(SessionStartParams.none()) + fun start(params: SessionStartParams): HttpResponseFor = + start(params, RequestOptions.none()) /** @see start */ @MustBeClosed fun start( - params: SessionStartParams = SessionStartParams.none(), + params: SessionStartParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor - - /** @see start */ - @MustBeClosed - fun start( - params: SessionStartParams = SessionStartParams.none() - ): HttpResponseFor = start(params, RequestOptions.none()) - - /** @see start */ - @MustBeClosed - fun start(requestOptions: RequestOptions): HttpResponseFor = - start(SessionStartParams.none(), requestOptions) } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index 467e9db..aac8272 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -4,6 +4,7 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.checkRequired import com.browserbase.api.core.handlers.errorBodyHandler import com.browserbase.api.core.handlers.errorHandler import com.browserbase.api.core.handlers.jsonHandler @@ -19,8 +20,8 @@ import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse import com.browserbase.api.models.sessions.SessionEndParams import com.browserbase.api.models.sessions.SessionEndResponse -import com.browserbase.api.models.sessions.SessionExecuteAgentParams -import com.browserbase.api.models.sessions.SessionExecuteAgentResponse +import com.browserbase.api.models.sessions.SessionExecuteParams +import com.browserbase.api.models.sessions.SessionExecuteResponse import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionExtractResponse import com.browserbase.api.models.sessions.SessionNavigateParams @@ -30,6 +31,7 @@ import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import java.util.function.Consumer +import kotlin.jvm.optionals.getOrNull class SessionServiceImpl internal constructor(private val clientOptions: ClientOptions) : SessionService { @@ -44,46 +46,46 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO SessionServiceImpl(clientOptions.toBuilder().apply(modifier::accept).build()) override fun act(params: SessionActParams, requestOptions: RequestOptions): SessionActResponse = - // post /sessions/{id}/act + // post /v1/sessions/{id}/act withRawResponse().act(params, requestOptions).parse() override fun end(params: SessionEndParams, requestOptions: RequestOptions): SessionEndResponse = - // post /sessions/{id}/end + // post /v1/sessions/{id}/end withRawResponse().end(params, requestOptions).parse() - override fun executeAgent( - params: SessionExecuteAgentParams, + override fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions, - ): SessionExecuteAgentResponse = - // post /sessions/{id}/agentExecute - withRawResponse().executeAgent(params, requestOptions).parse() + ): SessionExecuteResponse = + // post /v1/sessions/{id}/agentExecute + withRawResponse().execute(params, requestOptions).parse() override fun extract( params: SessionExtractParams, requestOptions: RequestOptions, ): SessionExtractResponse = - // post /sessions/{id}/extract + // post /v1/sessions/{id}/extract withRawResponse().extract(params, requestOptions).parse() override fun navigate( params: SessionNavigateParams, requestOptions: RequestOptions, ): SessionNavigateResponse = - // post /sessions/{id}/navigate + // post /v1/sessions/{id}/navigate withRawResponse().navigate(params, requestOptions).parse() override fun observe( params: SessionObserveParams, requestOptions: RequestOptions, ): SessionObserveResponse = - // post /sessions/{id}/observe + // post /v1/sessions/{id}/observe withRawResponse().observe(params, requestOptions).parse() override fun start( params: SessionStartParams, requestOptions: RequestOptions, ): SessionStartResponse = - // post /sessions/start + // post /v1/sessions/start withRawResponse().start(params, requestOptions).parse() class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : @@ -106,11 +108,14 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO params: SessionActParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "act") + .addPathSegments("v1", "sessions", params._pathParam(0), "act") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) @@ -134,11 +139,14 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO params: SessionEndParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "end") + .addPathSegments("v1", "sessions", params._pathParam(0), "end") .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } .build() .prepare(clientOptions, params) @@ -155,18 +163,21 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO } } - private val executeAgentHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val executeHandler: Handler = + jsonHandler(clientOptions.jsonMapper) - override fun executeAgent( - params: SessionExecuteAgentParams, + override fun execute( + params: SessionExecuteParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "agentExecute") + .addPathSegments("v1", "sessions", params._pathParam(0), "agentExecute") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) @@ -174,7 +185,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO val response = clientOptions.httpClient.execute(request, requestOptions) return errorHandler.handle(response).parseable { response - .use { executeAgentHandler.handle(it) } + .use { executeHandler.handle(it) } .also { if (requestOptions.responseValidation!!) { it.validate() @@ -190,11 +201,14 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO params: SessionExtractParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "extract") + .addPathSegments("v1", "sessions", params._pathParam(0), "extract") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) @@ -218,11 +232,14 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO params: SessionNavigateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "navigate") + .addPathSegments("v1", "sessions", params._pathParam(0), "navigate") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) @@ -246,11 +263,14 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO params: SessionObserveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", params._pathParam(0), "observe") + .addPathSegments("v1", "sessions", params._pathParam(0), "observe") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) @@ -278,7 +298,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO HttpRequest.builder() .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) - .addPathSegments("sessions", "start") + .addPathSegments("v1", "sessions", "start") .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 4b81e39..c31444c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -4,6 +4,7 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,20 +13,36 @@ internal class SessionActParamsTest { @Test fun create() { SessionActParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) .build() } @Test fun pathParams() { - val params = SessionActParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build() - assertThat(params._pathParam(0)).isEqualTo("[object Object]") + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param assertThat(params._pathParam(1)).isEqualTo("") } @@ -34,22 +51,46 @@ internal class SessionActParamsTest { fun headers() { val params = SessionActParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) .build() val headers = params._headers() - assertThat(headers).isEqualTo(Headers.builder().build()) + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) } @Test fun headersWithoutOptionalFields() { - val params = SessionActParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build() val headers = params._headers() @@ -60,23 +101,56 @@ internal class SessionActParamsTest { fun body() { val params = SessionActParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) .build() val body = params._body() - assertThat(body).isEqualTo(JsonValue.from(mapOf())) + assertThat(body.input()) + .isEqualTo(SessionActParams.Input.ofString("Click the login button")) + assertThat(body.frameId()).contains("frameId") + assertThat(body.options()) + .contains( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) } @Test fun bodyWithoutOptionalFields() { - val params = SessionActParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .input("Click the login button") + .build() val body = params._body() + + assertThat(body.input()) + .isEqualTo(SessionActParams.Input.ofString("Click the login button")) } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt index 83f3fa4..000d7fd 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt @@ -11,13 +11,82 @@ internal class SessionActResponseTest { @Test fun create() { - val sessionActResponse = SessionActResponse.builder().build() + val sessionActResponse = + SessionActResponse.builder() + .data( + SessionActResponse.Data.builder() + .result( + SessionActResponse.Data.Result.builder() + .actionDescription("Clicked button with text 'Login'") + .addAction( + Action.builder() + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") + .build() + ) + .message("Successfully clicked the login button") + .success(true) + .build() + ) + .actionId("actionId") + .build() + ) + .success(SessionActResponse.Success.TRUE) + .build() + + assertThat(sessionActResponse.data()) + .isEqualTo( + SessionActResponse.Data.builder() + .result( + SessionActResponse.Data.Result.builder() + .actionDescription("Clicked button with text 'Login'") + .addAction( + Action.builder() + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") + .build() + ) + .message("Successfully clicked the login button") + .success(true) + .build() + ) + .actionId("actionId") + .build() + ) + assertThat(sessionActResponse.success()).isEqualTo(SessionActResponse.Success.TRUE) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionActResponse = SessionActResponse.builder().build() + val sessionActResponse = + SessionActResponse.builder() + .data( + SessionActResponse.Data.builder() + .result( + SessionActResponse.Data.Result.builder() + .actionDescription("Clicked button with text 'Login'") + .addAction( + Action.builder() + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") + .build() + ) + .message("Successfully clicked the login button") + .success(true) + .build() + ) + .actionId("actionId") + .build() + ) + .success(SessionActResponse.Success.TRUE) + .build() val roundtrippedSessionActResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 514fc5e..14faac3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -2,8 +2,8 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,19 +12,19 @@ internal class SessionEndParamsTest { @Test fun create() { SessionEndParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() } @Test fun pathParams() { - val params = SessionEndParams.builder().id(JsonValue.from(mapOf())).build() + val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() - assertThat(params._pathParam(0)).isEqualTo("[object Object]") + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param assertThat(params._pathParam(1)).isEqualTo("") } @@ -33,21 +33,29 @@ internal class SessionEndParamsTest { fun headers() { val params = SessionEndParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() val headers = params._headers() - assertThat(headers).isEqualTo(Headers.builder().build()) + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) } @Test fun headersWithoutOptionalFields() { - val params = SessionEndParams.builder().id(JsonValue.from(mapOf())).build() + val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val headers = params._headers() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt index 30e45db..27a2a36 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt @@ -11,13 +11,17 @@ internal class SessionEndResponseTest { @Test fun create() { - val sessionEndResponse = SessionEndResponse.builder().build() + val sessionEndResponse = + SessionEndResponse.builder().success(SessionEndResponse.Success.TRUE).build() + + assertThat(sessionEndResponse.success()).isEqualTo(SessionEndResponse.Success.TRUE) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionEndResponse = SessionEndResponse.builder().build() + val sessionEndResponse = + SessionEndResponse.builder().success(SessionEndResponse.Success.TRUE).build() val roundtrippedSessionEndResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt deleted file mode 100644 index 90f1e1f..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentParamsTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.http.Headers -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionExecuteAgentParamsTest { - - @Test - fun create() { - SessionExecuteAgentParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) - .build() - } - - @Test - fun pathParams() { - val params = - SessionExecuteAgentParams.builder().id(JsonValue.from(mapOf())).build() - - assertThat(params._pathParam(0)).isEqualTo("[object Object]") - // out-of-bound path param - assertThat(params._pathParam(1)).isEqualTo("") - } - - @Test - fun headers() { - val params = - SessionExecuteAgentParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) - .build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun headersWithoutOptionalFields() { - val params = - SessionExecuteAgentParams.builder().id(JsonValue.from(mapOf())).build() - - val headers = params._headers() - - assertThat(headers).isEqualTo(Headers.builder().build()) - } - - @Test - fun body() { - val params = - SessionExecuteAgentParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) - .build() - - val body = params._body() - - assertThat(body).isEqualTo(JsonValue.from(mapOf())) - } - - @Test - fun bodyWithoutOptionalFields() { - val params = - SessionExecuteAgentParams.builder().id(JsonValue.from(mapOf())).build() - - val body = params._body() - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt deleted file mode 100644 index 0c28d46..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteAgentResponseTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.browserbase.api.models.sessions - -import com.browserbase.api.core.jsonMapper -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class SessionExecuteAgentResponseTest { - - @Test - fun create() { - val sessionExecuteAgentResponse = SessionExecuteAgentResponse.builder().build() - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val sessionExecuteAgentResponse = SessionExecuteAgentResponse.builder().build() - - val roundtrippedSessionExecuteAgentResponse = - jsonMapper.readValue( - jsonMapper.writeValueAsString(sessionExecuteAgentResponse), - jacksonTypeRef(), - ) - - assertThat(roundtrippedSessionExecuteAgentResponse).isEqualTo(sessionExecuteAgentResponse) - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt new file mode 100644 index 0000000..b40f381 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -0,0 +1,199 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExecuteParamsTest { + + @Test + fun create() { + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("string") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") + .build() + } + + @Test + fun pathParams() { + val params = + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .agentConfig(SessionExecuteParams.AgentConfig.builder().build()) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .build() + ) + .build() + + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("string") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") + .build() + + val headers = params._headers() + + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .agentConfig(SessionExecuteParams.AgentConfig.builder().build()) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .build() + ) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } + + @Test + fun body() { + val params = + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("string") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") + .build() + + val body = params._body() + + assertThat(body.agentConfig()) + .isEqualTo( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("string") + .systemPrompt("systemPrompt") + .build() + ) + assertThat(body.executeOptions()) + .isEqualTo( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + assertThat(body.frameId()).contains("frameId") + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .agentConfig(SessionExecuteParams.AgentConfig.builder().build()) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .build() + ) + .build() + + val body = params._body() + + assertThat(body.agentConfig()).isEqualTo(SessionExecuteParams.AgentConfig.builder().build()) + assertThat(body.executeOptions()) + .isEqualTo( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .build() + ) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt new file mode 100644 index 0000000..d2fb4d9 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt @@ -0,0 +1,151 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionExecuteResponseTest { + + @Test + fun create() { + val sessionExecuteResponse = + SessionExecuteResponse.builder() + .data( + SessionExecuteResponse.Data.builder() + .result( + SessionExecuteResponse.Data.Result.builder() + .addAction( + SessionExecuteResponse.Data.Result.Action.builder() + .type("click") + .action("action") + .instruction("instruction") + .pageText("pageText") + .pageUrl("pageUrl") + .reasoning("reasoning") + .taskCompleted(true) + .timeMs(0.0) + .build() + ) + .completed(true) + .message("Successfully logged in and navigated to dashboard") + .success(true) + .metadata( + SessionExecuteResponse.Data.Result.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .usage( + SessionExecuteResponse.Data.Result.Usage.builder() + .inferenceTimeMs(2500.0) + .inputTokens(1500.0) + .outputTokens(250.0) + .cachedInputTokens(0.0) + .reasoningTokens(0.0) + .build() + ) + .build() + ) + .build() + ) + .success(SessionExecuteResponse.Success.TRUE) + .build() + + assertThat(sessionExecuteResponse.data()) + .isEqualTo( + SessionExecuteResponse.Data.builder() + .result( + SessionExecuteResponse.Data.Result.builder() + .addAction( + SessionExecuteResponse.Data.Result.Action.builder() + .type("click") + .action("action") + .instruction("instruction") + .pageText("pageText") + .pageUrl("pageUrl") + .reasoning("reasoning") + .taskCompleted(true) + .timeMs(0.0) + .build() + ) + .completed(true) + .message("Successfully logged in and navigated to dashboard") + .success(true) + .metadata( + SessionExecuteResponse.Data.Result.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .usage( + SessionExecuteResponse.Data.Result.Usage.builder() + .inferenceTimeMs(2500.0) + .inputTokens(1500.0) + .outputTokens(250.0) + .cachedInputTokens(0.0) + .reasoningTokens(0.0) + .build() + ) + .build() + ) + .build() + ) + assertThat(sessionExecuteResponse.success()).isEqualTo(SessionExecuteResponse.Success.TRUE) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionExecuteResponse = + SessionExecuteResponse.builder() + .data( + SessionExecuteResponse.Data.builder() + .result( + SessionExecuteResponse.Data.Result.builder() + .addAction( + SessionExecuteResponse.Data.Result.Action.builder() + .type("click") + .action("action") + .instruction("instruction") + .pageText("pageText") + .pageUrl("pageUrl") + .reasoning("reasoning") + .taskCompleted(true) + .timeMs(0.0) + .build() + ) + .completed(true) + .message("Successfully logged in and navigated to dashboard") + .success(true) + .metadata( + SessionExecuteResponse.Data.Result.Metadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .usage( + SessionExecuteResponse.Data.Result.Usage.builder() + .inferenceTimeMs(2500.0) + .inputTokens(1500.0) + .outputTokens(250.0) + .cachedInputTokens(0.0) + .reasoningTokens(0.0) + .build() + ) + .build() + ) + .build() + ) + .success(SessionExecuteResponse.Success.TRUE) + .build() + + val roundtrippedSessionExecuteResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionExecuteResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionExecuteResponse).isEqualTo(sessionExecuteResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index e631276..4a3c252 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -4,6 +4,7 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,20 +13,34 @@ internal class SessionExtractParamsTest { @Test fun create() { SessionExtractParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("string") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() } @Test fun pathParams() { - val params = SessionExtractParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionExtractParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() - assertThat(params._pathParam(0)).isEqualTo("[object Object]") + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param assertThat(params._pathParam(1)).isEqualTo("") } @@ -34,22 +49,44 @@ internal class SessionExtractParamsTest { fun headers() { val params = SessionExtractParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("string") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() val headers = params._headers() - assertThat(headers).isEqualTo(Headers.builder().build()) + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) } @Test fun headersWithoutOptionalFields() { - val params = SessionExtractParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionExtractParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val headers = params._headers() @@ -60,22 +97,52 @@ internal class SessionExtractParamsTest { fun body() { val params = SessionExtractParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("string") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() val body = params._body() - assertThat(body).isEqualTo(JsonValue.from(mapOf())) + assertThat(body.frameId()).contains("frameId") + assertThat(body.instruction()) + .contains("Extract all product names and prices from the page") + assertThat(body.options()) + .contains( + SessionExtractParams.Options.builder() + .model("string") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + assertThat(body.schema()) + .contains( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) } @Test fun bodyWithoutOptionalFields() { - val params = SessionExtractParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionExtractParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val body = params._body() } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt index 04bed64..6cf7056 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat @@ -11,13 +12,40 @@ internal class SessionExtractResponseTest { @Test fun create() { - val sessionExtractResponse = SessionExtractResponse.builder().build() + val sessionExtractResponse = + SessionExtractResponse.builder() + .data( + SessionExtractResponse.Data.builder() + .result(JsonValue.from(mapOf())) + .actionId("actionId") + .build() + ) + .success(SessionExtractResponse.Success.TRUE) + .build() + + assertThat(sessionExtractResponse.data()) + .isEqualTo( + SessionExtractResponse.Data.builder() + .result(JsonValue.from(mapOf())) + .actionId("actionId") + .build() + ) + assertThat(sessionExtractResponse.success()).isEqualTo(SessionExtractResponse.Success.TRUE) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionExtractResponse = SessionExtractResponse.builder().build() + val sessionExtractResponse = + SessionExtractResponse.builder() + .data( + SessionExtractResponse.Data.builder() + .result(JsonValue.from(mapOf())) + .actionId("actionId") + .build() + ) + .success(SessionExtractResponse.Success.TRUE) + .build() val roundtrippedSessionExtractResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt index 6d8a60d..aa845c3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -2,8 +2,8 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,21 +12,32 @@ internal class SessionNavigateParamsTest { @Test fun create() { SessionNavigateParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .referer("referer") + .timeout(30000.0) + .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) + .build() + ) .build() } @Test fun pathParams() { val params = - SessionNavigateParams.builder().id(JsonValue.from(mapOf())).build() + SessionNavigateParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .url("https://example.com") + .build() - assertThat(params._pathParam(0)).isEqualTo("[object Object]") + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param assertThat(params._pathParam(1)).isEqualTo("") } @@ -35,23 +46,42 @@ internal class SessionNavigateParamsTest { fun headers() { val params = SessionNavigateParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .referer("referer") + .timeout(30000.0) + .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) + .build() + ) .build() val headers = params._headers() - assertThat(headers).isEqualTo(Headers.builder().build()) + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) } @Test fun headersWithoutOptionalFields() { val params = - SessionNavigateParams.builder().id(JsonValue.from(mapOf())).build() + SessionNavigateParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .url("https://example.com") + .build() val headers = params._headers() @@ -62,24 +92,46 @@ internal class SessionNavigateParamsTest { fun body() { val params = SessionNavigateParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .referer("referer") + .timeout(30000.0) + .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) + .build() + ) .build() val body = params._body() - assertThat(body).isEqualTo(JsonValue.from(mapOf())) + assertThat(body.url()).isEqualTo("https://example.com") + assertThat(body.frameId()).contains("frameId") + assertThat(body.options()) + .contains( + SessionNavigateParams.Options.builder() + .referer("referer") + .timeout(30000.0) + .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) + .build() + ) } @Test fun bodyWithoutOptionalFields() { val params = - SessionNavigateParams.builder().id(JsonValue.from(mapOf())).build() + SessionNavigateParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .url("https://example.com") + .build() val body = params._body() + + assertThat(body.url()).isEqualTo("https://example.com") } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt index 6d62909..e02a0e3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat @@ -11,13 +12,41 @@ internal class SessionNavigateResponseTest { @Test fun create() { - val sessionNavigateResponse = SessionNavigateResponse.builder().build() + val sessionNavigateResponse = + SessionNavigateResponse.builder() + .data( + SessionNavigateResponse.Data.builder() + .result(JsonValue.from(mapOf())) + .actionId("actionId") + .build() + ) + .success(SessionNavigateResponse.Success.TRUE) + .build() + + assertThat(sessionNavigateResponse.data()) + .isEqualTo( + SessionNavigateResponse.Data.builder() + .result(JsonValue.from(mapOf())) + .actionId("actionId") + .build() + ) + assertThat(sessionNavigateResponse.success()) + .isEqualTo(SessionNavigateResponse.Success.TRUE) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionNavigateResponse = SessionNavigateResponse.builder().build() + val sessionNavigateResponse = + SessionNavigateResponse.builder() + .data( + SessionNavigateResponse.Data.builder() + .result(JsonValue.from(mapOf())) + .actionId("actionId") + .build() + ) + .success(SessionNavigateResponse.Success.TRUE) + .build() val roundtrippedSessionNavigateResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 8943f1d..95ccd9b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -2,8 +2,8 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,20 +12,29 @@ internal class SessionObserveParamsTest { @Test fun create() { SessionObserveParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("string") + .selector("nav") + .timeout(30000.0) + .build() + ) .build() } @Test fun pathParams() { - val params = SessionObserveParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionObserveParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() - assertThat(params._pathParam(0)).isEqualTo("[object Object]") + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param assertThat(params._pathParam(1)).isEqualTo("") } @@ -34,22 +43,39 @@ internal class SessionObserveParamsTest { fun headers() { val params = SessionObserveParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("string") + .selector("nav") + .timeout(30000.0) + .build() + ) .build() val headers = params._headers() - assertThat(headers).isEqualTo(Headers.builder().build()) + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) } @Test fun headersWithoutOptionalFields() { - val params = SessionObserveParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionObserveParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val headers = params._headers() @@ -60,22 +86,40 @@ internal class SessionObserveParamsTest { fun body() { val params = SessionObserveParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("string") + .selector("nav") + .timeout(30000.0) + .build() + ) .build() val body = params._body() - assertThat(body).isEqualTo(JsonValue.from(mapOf())) + assertThat(body.frameId()).contains("frameId") + assertThat(body.instruction()).contains("Find all clickable navigation links") + assertThat(body.options()) + .contains( + SessionObserveParams.Options.builder() + .model("string") + .selector("nav") + .timeout(30000.0) + .build() + ) } @Test fun bodyWithoutOptionalFields() { - val params = SessionObserveParams.builder().id(JsonValue.from(mapOf())).build() + val params = + SessionObserveParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val body = params._body() } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt index b597689..e3d72c3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt @@ -11,13 +11,61 @@ internal class SessionObserveResponseTest { @Test fun create() { - val sessionObserveResponse = SessionObserveResponse.builder().build() + val sessionObserveResponse = + SessionObserveResponse.builder() + .data( + SessionObserveResponse.Data.builder() + .addResult( + Action.builder() + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") + .build() + ) + .actionId("actionId") + .build() + ) + .success(SessionObserveResponse.Success.TRUE) + .build() + + assertThat(sessionObserveResponse.data()) + .isEqualTo( + SessionObserveResponse.Data.builder() + .addResult( + Action.builder() + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") + .build() + ) + .actionId("actionId") + .build() + ) + assertThat(sessionObserveResponse.success()).isEqualTo(SessionObserveResponse.Success.TRUE) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionObserveResponse = SessionObserveResponse.builder().build() + val sessionObserveResponse = + SessionObserveResponse.builder() + .data( + SessionObserveResponse.Data.builder() + .addResult( + Action.builder() + .description("Click the submit button") + .selector("[data-testid='submit-button']") + .addArgument("Hello World") + .method("click") + .build() + ) + .actionId("actionId") + .build() + ) + .success(SessionObserveResponse.Success.TRUE) + .build() val roundtrippedSessionObserveResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 627f9ae..13ae538 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -4,6 +4,7 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -12,11 +13,148 @@ internal class SessionStartParamsTest { @Test fun create() { SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings.builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region(SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() } @@ -24,21 +162,170 @@ internal class SessionStartParamsTest { fun headers() { val params = SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region(SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() val headers = params._headers() - assertThat(headers).isEqualTo(Headers.builder().build()) + assertThat(headers) + .isEqualTo( + Headers.builder() + .put("x-language", "typescript") + .put("x-sdk-version", "3.0.6") + .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-stream-response", "true") + .build() + ) } @Test fun headersWithoutOptionalFields() { - val params = SessionStartParams.builder().build() + val params = SessionStartParams.builder().modelName("gpt-4o").build() val headers = params._headers() @@ -49,22 +336,304 @@ internal class SessionStartParamsTest { fun body() { val params = SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region(SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() val body = params._body() - assertThat(body).isEqualTo(JsonValue.from(mapOf())) + assertThat(body.modelName()).isEqualTo("gpt-4o") + assertThat(body.actTimeoutMs()).contains(30000.0) + assertThat(body.browser()) + .contains( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + assertThat(body.browserbaseSessionCreateParams()) + .contains( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings.builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region(SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + assertThat(body.browserbaseSessionId()).contains("browserbaseSessionID") + assertThat(body.debugDom()).contains(true) + assertThat(body.domSettleTimeoutMs()).contains(5000.0) + assertThat(body.experimental()).contains(true) + assertThat(body.selfHeal()).contains(true) + assertThat(body.systemPrompt()).contains("systemPrompt") + assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) + assertThat(body.waitForCaptchaSolves()).contains(true) } @Test fun bodyWithoutOptionalFields() { - val params = SessionStartParams.builder().build() + val params = SessionStartParams.builder().modelName("gpt-4o").build() val body = params._body() + + assertThat(body.modelName()).isEqualTo("gpt-4o") } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt index 51616d7..717d6d6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt @@ -11,13 +11,40 @@ internal class SessionStartResponseTest { @Test fun create() { - val sessionStartResponse = SessionStartResponse.builder().build() + val sessionStartResponse = + SessionStartResponse.builder() + .data( + SessionStartResponse.Data.builder() + .available(true) + .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .build() + ) + .success(SessionStartResponse.Success.TRUE) + .build() + + assertThat(sessionStartResponse.data()) + .isEqualTo( + SessionStartResponse.Data.builder() + .available(true) + .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .build() + ) + assertThat(sessionStartResponse.success()).isEqualTo(SessionStartResponse.Success.TRUE) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionStartResponse = SessionStartResponse.builder().build() + val sessionStartResponse = + SessionStartResponse.builder() + .data( + SessionStartResponse.Data.builder() + .available(true) + .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .build() + ) + .success(SessionStartResponse.Success.TRUE) + .build() val roundtrippedSessionStartResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index ccf1223..32b00d3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -16,13 +16,14 @@ import com.browserbase.api.errors.StagehandException import com.browserbase.api.errors.UnauthorizedException import com.browserbase.api.errors.UnexpectedStatusCodeException import com.browserbase.api.errors.UnprocessableEntityException -import com.browserbase.api.models.sessions.SessionStartParams +import com.browserbase.api.models.sessions.SessionActParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.post import com.github.tomakehurst.wiremock.client.WireMock.status import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.entry import org.junit.jupiter.api.BeforeEach @@ -61,7 +62,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart400() { + fun sessionsAct400() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -72,13 +73,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -89,7 +106,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart400WithRawResponse() { + fun sessionsAct400WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -100,13 +117,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -117,7 +150,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart401() { + fun sessionsAct401() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -128,13 +161,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -145,7 +194,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart401WithRawResponse() { + fun sessionsAct401WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -156,13 +205,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -173,7 +238,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart403() { + fun sessionsAct403() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -184,13 +249,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -201,7 +282,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart403WithRawResponse() { + fun sessionsAct403WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -212,13 +293,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -229,7 +326,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart404() { + fun sessionsAct404() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -240,13 +337,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -257,7 +370,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart404WithRawResponse() { + fun sessionsAct404WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -268,13 +381,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -285,7 +414,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart422() { + fun sessionsAct422() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -296,13 +425,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -313,7 +458,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart422WithRawResponse() { + fun sessionsAct422WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -324,13 +469,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -341,7 +502,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart429() { + fun sessionsAct429() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -352,13 +513,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -369,7 +546,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart429WithRawResponse() { + fun sessionsAct429WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -380,13 +557,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -397,7 +590,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart500() { + fun sessionsAct500() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -408,13 +601,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -425,7 +634,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart500WithRawResponse() { + fun sessionsAct500WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -436,13 +645,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -453,7 +678,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart999() { + fun sessionsAct999() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -464,13 +689,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -481,7 +722,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStart999WithRawResponse() { + fun sessionsAct999WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -492,13 +733,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } @@ -509,7 +766,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsStartInvalidJsonBody() { + fun sessionsActInvalidJsonBody() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -518,13 +775,29 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from("john_doe"), + ) + .build() + ) + .build() + ) .build() ) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 8af7ae3..060d011 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -5,9 +5,10 @@ package com.browserbase.api.services import com.browserbase.api.client.StagehandClient import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue -import com.browserbase.api.models.sessions.SessionStartParams +import com.browserbase.api.models.sessions.SessionActParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.equalTo +import com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath import com.github.tomakehurst.wiremock.client.WireMock.ok import com.github.tomakehurst.wiremock.client.WireMock.post import com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor @@ -15,6 +16,7 @@ import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.client.WireMock.verify import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest +import java.time.OffsetDateTime import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -39,19 +41,33 @@ internal class ServiceParamsTest { @Disabled("Prism tests are disabled") @Test - fun start() { + fun act() { val sessionService = client.sessions() stubFor(post(anyUrl()).willReturn(ok("{}"))) - sessionService.start( - SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.act( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") + .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) .build() ) @@ -59,6 +75,7 @@ internal class ServiceParamsTest { postRequestedFor(anyUrl()) .withHeader("Secret-Header", equalTo("42")) .withQueryParam("secret_query_param", equalTo("42")) + .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) ) } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index dba84aa..0011f6f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -7,11 +7,12 @@ import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionEndParams -import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteParams import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams +import java.time.OffsetDateTime import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -34,12 +35,24 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.act( SessionActParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) .build() ) @@ -62,11 +75,11 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.end( SessionEndParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() ) @@ -76,7 +89,7 @@ internal class SessionServiceAsyncTest { @Disabled("Prism tests are disabled") @Test - fun executeAgent() { + fun execute() { val client = StagehandOkHttpClientAsync.builder() .baseUrl(TestServerExtension.BASE_URL) @@ -87,14 +100,30 @@ internal class SessionServiceAsyncTest { val sessionServiceAsync = client.sessions() val responseFuture = - sessionServiceAsync.executeAgent( - SessionExecuteAgentParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionServiceAsync.execute( + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("string") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") .build() ) @@ -117,12 +146,25 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.extract( SessionExtractParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("string") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() ) @@ -145,12 +187,20 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.navigate( SessionNavigateParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .referer("referer") + .timeout(30000.0) + .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) + .build() + ) .build() ) @@ -173,12 +223,20 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.observe( SessionObserveParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("string") + .selector("nav") + .timeout(30000.0) + .build() + ) .build() ) @@ -201,11 +259,155 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.start( SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 03853cd..3f62ca6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -7,11 +7,12 @@ import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionEndParams -import com.browserbase.api.models.sessions.SessionExecuteAgentParams +import com.browserbase.api.models.sessions.SessionExecuteParams import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams +import java.time.OffsetDateTime import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -34,12 +35,24 @@ internal class SessionServiceTest { val response = sessionService.act( SessionActParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("string") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) .build() ) @@ -61,11 +74,11 @@ internal class SessionServiceTest { val response = sessionService.end( SessionEndParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() ) @@ -74,7 +87,7 @@ internal class SessionServiceTest { @Disabled("Prism tests are disabled") @Test - fun executeAgent() { + fun execute() { val client = StagehandOkHttpClient.builder() .baseUrl(TestServerExtension.BASE_URL) @@ -85,14 +98,30 @@ internal class SessionServiceTest { val sessionService = client.sessions() val response = - sessionService.executeAgent( - SessionExecuteAgentParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + sessionService.execute( + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("string") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") .build() ) @@ -114,12 +143,25 @@ internal class SessionServiceTest { val response = sessionService.extract( SessionExtractParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("string") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() ) @@ -141,12 +183,20 @@ internal class SessionServiceTest { val response = sessionService.navigate( SessionNavigateParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) + .url("https://example.com") + .frameId("frameId") + .options( + SessionNavigateParams.Options.builder() + .referer("referer") + .timeout(30000.0) + .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) + .build() + ) .build() ) @@ -168,12 +218,20 @@ internal class SessionServiceTest { val response = sessionService.observe( SessionObserveParams.builder() - .id(JsonValue.from(mapOf())) - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("string") + .selector("nav") + .timeout(30000.0) + .build() + ) .build() ) @@ -195,11 +253,155 @@ internal class SessionServiceTest { val response = sessionService.start( SessionStartParams.builder() - .xLanguage(JsonValue.from(mapOf())) - .xSdkVersion(JsonValue.from(mapOf())) - .xSentAt(JsonValue.from(mapOf())) - .xStreamResponse(JsonValue.from(mapOf())) - .body(JsonValue.from(mapOf())) + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) From 1e1103ad96d014246c17a6ddc531fd9568f95354 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:22:21 +0000 Subject: [PATCH 030/164] feat(api): manual updates --- .stats.yml | 6 +- README.md | 28 +- .../api/services/ErrorHandlingTest.kt | 2892 +++++++++++++++-- .../api/services/ServiceParamsTest.kt | 169 + 4 files changed, 2788 insertions(+), 307 deletions(-) diff --git a/.stats.yml b/.stats.yml index 87bd24b..a5338dd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-349e1b0f6291eedd731c1660155a50adcb3424fb8cd9e17bbdc0939ff3bbffcd.yml -openapi_spec_hash: 456b593ea71d72bc31a6338a25363e9f -config_hash: 5f6b5ec6e84fb01932ba87c6a9623d9b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e6a9dca1a93568e403ac72128d86f30c8c3f1336d4b67017d7e61b1836f10f47.yml +openapi_spec_hash: ef01e0649bb0e283df0aa81c369649df +config_hash: abc9d1eb9779bb5629eaed7074c42809 diff --git a/README.md b/README.md index 019da3c..852c752 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .input("Click the login button") + .input("click the first link on the page") .build(); SessionActResponse response = client.sessions().act(params); ``` @@ -163,7 +163,7 @@ StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .input("Click the login button") + .input("click the first link on the page") .build(); CompletableFuture response = client.async().sessions().act(params); ``` @@ -183,7 +183,7 @@ StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); SessionActParams params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .input("Click the login button") + .input("click the first link on the page") .build(); CompletableFuture response = client.sessions().act(params); ``` @@ -199,14 +199,13 @@ To access this data, prefix any HTTP method call on a client or service with `wi ```java import com.browserbase.api.core.http.Headers; import com.browserbase.api.core.http.HttpResponseFor; -import com.browserbase.api.models.sessions.SessionActParams; -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartParams; +import com.browserbase.api.models.sessions.SessionStartResponse; -SessionActParams params = SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .input("Click the login button") +SessionStartParams params = SessionStartParams.builder() + .modelName("gpt-4o") .build(); -HttpResponseFor response = client.sessions().withRawResponse().act(params); +HttpResponseFor response = client.sessions().withRawResponse().start(params); int statusCode = response.statusCode(); Headers headers = response.headers(); @@ -215,9 +214,9 @@ Headers headers = response.headers(); You can still deserialize the response into an instance of a Java class if needed: ```java -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; -SessionActResponse parsedResponse = response.parse(); +SessionStartResponse parsedResponse = response.parse(); ``` ## Error handling @@ -313,9 +312,9 @@ Requests time out after 1 minute by default. To set a custom timeout, configure the method call using the `timeout` method: ```java -import com.browserbase.api.models.sessions.SessionActResponse; +import com.browserbase.api.models.sessions.SessionStartResponse; -SessionActResponse response = client.sessions().act( +SessionStartResponse response = client.sessions().start( params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() ); ``` @@ -449,10 +448,11 @@ These properties can be accessed on the nested built object later using the `_ad To set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Values.kt) object to its setter: ```java +import com.browserbase.api.core.JsonValue; import com.browserbase.api.models.sessions.SessionActParams; SessionActParams params = SessionActParams.builder() - .input("Click the login button") + .input(JsonValue.from(42)) .build(); ``` diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 32b00d3..87af3f1 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -16,7 +16,7 @@ import com.browserbase.api.errors.StagehandException import com.browserbase.api.errors.UnauthorizedException import com.browserbase.api.errors.UnexpectedStatusCodeException import com.browserbase.api.errors.UnprocessableEntityException -import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.post import com.github.tomakehurst.wiremock.client.WireMock.status @@ -62,7 +62,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct400() { + fun sessionsStart400() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -73,29 +73,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -106,7 +242,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct400WithRawResponse() { + fun sessionsStart400WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -117,29 +253,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -150,7 +422,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct401() { + fun sessionsStart401() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -161,29 +433,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -194,7 +602,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct401WithRawResponse() { + fun sessionsStart401WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -205,29 +613,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -238,7 +782,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct403() { + fun sessionsStart403() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -249,29 +793,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -282,7 +962,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct403WithRawResponse() { + fun sessionsStart403WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -293,29 +973,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -326,7 +1142,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct404() { + fun sessionsStart404() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -337,29 +1153,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -370,7 +1322,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct404WithRawResponse() { + fun sessionsStart404WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -381,29 +1333,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -414,7 +1502,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct422() { + fun sessionsStart422() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -425,29 +1513,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -458,7 +1682,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct422WithRawResponse() { + fun sessionsStart422WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -469,29 +1693,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -502,7 +1862,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct429() { + fun sessionsStart429() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -513,29 +1873,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -546,7 +2042,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct429WithRawResponse() { + fun sessionsStart429WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -557,29 +2053,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -590,7 +2222,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct500() { + fun sessionsStart500() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -601,29 +2233,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -634,7 +2402,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct500WithRawResponse() { + fun sessionsStart500WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -645,29 +2413,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) .build() ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -678,7 +2582,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct999() { + fun sessionsStart999() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -689,29 +2593,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -722,7 +2762,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsAct999WithRawResponse() { + fun sessionsStart999WithRawResponse() { val sessionService = client.sessions().withRawResponse() stubFor( post(anyUrl()) @@ -733,29 +2773,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() ) .build() ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } @@ -766,7 +2942,7 @@ internal class ErrorHandlingTest { } @Test - fun sessionsActInvalidJsonBody() { + fun sessionsStartInvalidJsonBody() { val sessionService = client.sessions() stubFor( post(anyUrl()) @@ -775,29 +2951,165 @@ internal class ErrorHandlingTest { val e = assertThrows { - sessionService.act( - SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) - .xStreamResponse(SessionActParams.XStreamResponse.TRUE) - .input("Click the login button") - .frameId("frameId") - .options( - SessionActParams.Options.builder() - .model("string") - .timeout(30000.0) - .variables( - SessionActParams.Options.Variables.builder() - .putAdditionalProperty( - "username", - JsonValue.from("john_doe"), + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams + .BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region( + SessionStartParams.BrowserbaseSessionCreateParams.Region + .US_WEST_2 + ) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) .build() ) .build() ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) .build() ) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 060d011..ecf30b0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -6,6 +6,7 @@ import com.browserbase.api.client.StagehandClient import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.SessionActParams +import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl import com.github.tomakehurst.wiremock.client.WireMock.equalTo import com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath @@ -39,6 +40,174 @@ internal class ServiceParamsTest { .build() } + @Disabled("Prism tests are disabled") + @Test + fun start() { + val sessionService = client.sessions() + stubFor(post(anyUrl()).willReturn(ok("{}"))) + + sessionService.start( + SessionStartParams.builder() + .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) + .modelName("gpt-4o") + .actTimeoutMs(30000.0) + .browser( + SessionStartParams.Browser.builder() + .cdpUrl("ws://localhost:9222") + .launchOptions( + SessionStartParams.Browser.LaunchOptions.builder() + .acceptDownloads(true) + .addArg("string") + .cdpUrl("cdpUrl") + .chromiumSandbox(true) + .connectTimeoutMs(0.0) + .deviceScaleFactor(0.0) + .devtools(true) + .downloadsPath("downloadsPath") + .executablePath("executablePath") + .hasTouch(true) + .headless(true) + .ignoreDefaultArgs(true) + .ignoreHttpsErrors(true) + .locale("locale") + .preserveUserDataDir(true) + .proxy( + SessionStartParams.Browser.LaunchOptions.Proxy.builder() + .server("server") + .bypass("bypass") + .password("password") + .username("username") + .build() + ) + .userDataDir("userDataDir") + .viewport( + SessionStartParams.Browser.LaunchOptions.Viewport.builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .type(SessionStartParams.Browser.Type.LOCAL) + .build() + ) + .browserbaseSessionCreateParams( + SessionStartParams.BrowserbaseSessionCreateParams.builder() + .browserSettings( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings + .builder() + .advancedStealth(true) + .blockAds(true) + .context( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Context + .builder() + .id("id") + .persist(true) + .build() + ) + .extensionId("extensionId") + .fingerprint( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .builder() + .addBrowser( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Browser + .CHROME + ) + .addDevice( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Device + .DESKTOP + ) + .httpVersion( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .HttpVersion + ._1 + ) + .addLocale("string") + .addOperatingSystem( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .OperatingSystem + .ANDROID + ) + .screen( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Fingerprint + .Screen + .builder() + .maxHeight(0.0) + .maxWidth(0.0) + .minHeight(0.0) + .minWidth(0.0) + .build() + ) + .build() + ) + .logSession(true) + .recordSession(true) + .solveCaptchas(true) + .viewport( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Viewport + .builder() + .height(0.0) + .width(0.0) + .build() + ) + .build() + ) + .extensionId("extensionId") + .keepAlive(true) + .projectId("projectId") + .proxies(true) + .region(SessionStartParams.BrowserbaseSessionCreateParams.Region.US_WEST_2) + .timeout(0.0) + .userMetadata( + SessionStartParams.BrowserbaseSessionCreateParams.UserMetadata.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + .browserbaseSessionId("browserbaseSessionID") + .debugDom(true) + .domSettleTimeoutMs(5000.0) + .experimental(true) + .selfHeal(true) + .systemPrompt("systemPrompt") + .verbose(SessionStartParams.Verbose._1) + .waitForCaptchaSolves(true) + .putAdditionalHeader("Secret-Header", "42") + .putAdditionalQueryParam("secret_query_param", "42") + .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) + .build() + ) + + verify( + postRequestedFor(anyUrl()) + .withHeader("Secret-Header", equalTo("42")) + .withQueryParam("secret_query_param", equalTo("42")) + .withRequestBody(matchingJsonPath("$.secretProperty", equalTo("42"))) + ) + } + @Disabled("Prism tests are disabled") @Test fun act() { From 823a32ff0a4852efe1f2fc9795960a07b41a0edb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:24:23 +0000 Subject: [PATCH 031/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index a5338dd..4bcf91f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e6a9dca1a93568e403ac72128d86f30c8c3f1336d4b67017d7e61b1836f10f47.yml openapi_spec_hash: ef01e0649bb0e283df0aa81c369649df -config_hash: abc9d1eb9779bb5629eaed7074c42809 +config_hash: 0f2a6f228fb92683466c107fce3bcd21 diff --git a/README.md b/README.md index 852c752..15d5186 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ import com.browserbase.api.models.sessions.SessionActResponse; StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .id("00000000-your-session-id-000000000000") .input("click the first link on the page") .build(); SessionActResponse response = client.sessions().act(params); @@ -162,7 +162,7 @@ import java.util.concurrent.CompletableFuture; StagehandClient client = StagehandOkHttpClient.fromEnv(); SessionActParams params = SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .id("00000000-your-session-id-000000000000") .input("click the first link on the page") .build(); CompletableFuture response = client.async().sessions().act(params); @@ -182,7 +182,7 @@ import java.util.concurrent.CompletableFuture; StagehandClientAsync client = StagehandOkHttpClientAsync.fromEnv(); SessionActParams params = SessionActParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .id("00000000-your-session-id-000000000000") .input("click the first link on the page") .build(); CompletableFuture response = client.sessions().act(params); From ba1799c5ab8b7966a83b07c967ffc7b6628a48d0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:26:29 +0000 Subject: [PATCH 032/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4bcf91f..2790605 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e6a9dca1a93568e403ac72128d86f30c8c3f1336d4b67017d7e61b1836f10f47.yml openapi_spec_hash: ef01e0649bb0e283df0aa81c369649df -config_hash: 0f2a6f228fb92683466c107fce3bcd21 +config_hash: 88e87ba7021be93d267ecfc8f5e6b891 diff --git a/README.md b/README.md index 15d5186..3c37038 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() - .modelName("gpt-4o") + .modelName("openai/gpt-5-nano") .build(); HttpResponseFor response = client.sessions().withRawResponse().start(params); From f2b36ecc1807908474cf4a0b862828fb8dc7f050 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:46:23 +0000 Subject: [PATCH 033/164] feat(api): manual updates --- .stats.yml | 4 +- .../main/kotlin/stagehand.publish.gradle.kts | 2 +- .../api/models/sessions/SessionActResponse.kt | 143 +---- .../api/models/sessions/SessionEndResponse.kt | 190 +----- .../models/sessions/SessionExecuteResponse.kt | 143 +---- .../models/sessions/SessionExtractResponse.kt | 143 +---- .../sessions/SessionNavigateResponse.kt | 143 +---- .../models/sessions/SessionObserveResponse.kt | 143 +---- .../api/models/sessions/SessionStartParams.kt | 546 +++--------------- .../models/sessions/SessionStartResponse.kt | 143 +---- .../models/sessions/SessionActResponseTest.kt | 6 +- .../models/sessions/SessionEndResponseTest.kt | 8 +- .../sessions/SessionExecuteResponseTest.kt | 6 +- .../sessions/SessionExtractResponseTest.kt | 6 +- .../sessions/SessionNavigateResponseTest.kt | 7 +- .../sessions/SessionObserveResponseTest.kt | 6 +- .../models/sessions/SessionStartParamsTest.kt | 8 +- .../sessions/SessionStartResponseTest.kt | 6 +- .../api/services/ErrorHandlingTest.kt | 34 +- .../api/services/ServiceParamsTest.kt | 2 +- .../services/async/SessionServiceAsyncTest.kt | 2 +- .../services/blocking/SessionServiceTest.kt | 2 +- 22 files changed, 229 insertions(+), 1464 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2790605..08f0cef 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e6a9dca1a93568e403ac72128d86f30c8c3f1336d4b67017d7e61b1836f10f47.yml -openapi_spec_hash: ef01e0649bb0e283df0aa81c369649df +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-d571232203ef4e00986a3245224267db6f8aaffdad57780f712e0694dc8d9e37.yml +openapi_spec_hash: d5d635dd7b24a2e1255c6f2a895253ff config_hash: 88e87ba7021be93d267ecfc8f5e6b891 diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index 796aad4..7b0ce3f 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -10,7 +10,7 @@ configure { pom { name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA].") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") url.set("https://docs.stagehand.dev") licenses { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt index bfa1f65..db27614 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -24,14 +23,14 @@ class SessionActResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val data: JsonField, - private val success: JsonField, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), ) : this(data, success, mutableMapOf()) /** @@ -41,10 +40,12 @@ private constructor( fun data(): Data = data.getRequired("data") /** + * Indicates whether the request was successful + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun success(): Success = success.getRequired("success") + fun success(): Boolean = success.getRequired("success") /** * Returns the raw JSON value of [data]. @@ -58,7 +59,7 @@ private constructor( * * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -90,7 +91,7 @@ private constructor( class Builder internal constructor() { private var data: JsonField? = null - private var success: JsonField? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -110,15 +111,16 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - fun success(success: Success) = success(JsonField.of(success)) + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) /** * Sets [Builder.success] to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -168,7 +170,7 @@ private constructor( } data().validate() - success().validate() + success() validated = true } @@ -187,8 +189,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + - (success.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -690,124 +691,6 @@ private constructor( "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" } - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt index 3bed0ac..3345222 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -2,12 +2,9 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing -import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -15,32 +12,29 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects -import kotlin.jvm.optionals.getOrNull class SessionEndResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val success: JsonField, + private val success: JsonValue, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of() + @JsonProperty("success") @ExcludeMissing success: JsonValue = JsonMissing.of() ) : this(success, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun success(): Success = success.getRequired("success") - - /** - * Returns the raw JSON value of [success]. + * Expected to always return the following: + * ```java + * JsonValue.from(true) + * ``` * - * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + * However, this method can be useful for debugging and logging (e.g. if the server responded + * with an unexpected value). */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonValue = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -56,21 +50,14 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [SessionEndResponse]. - * - * The following fields are required: - * ```java - * .success() - * ``` - */ + /** Returns a mutable builder for constructing an instance of [SessionEndResponse]. */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionEndResponse]. */ class Builder internal constructor() { - private var success: JsonField? = null + private var success: JsonValue = JsonValue.from(true) private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -79,15 +66,19 @@ private constructor( additionalProperties = sessionEndResponse.additionalProperties.toMutableMap() } - fun success(success: Success) = success(JsonField.of(success)) - /** - * Sets [Builder.success] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from(true) + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonValue) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -112,19 +103,9 @@ private constructor( * Returns an immutable instance of [SessionEndResponse]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .success() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): SessionEndResponse = - SessionEndResponse( - checkRequired("success", success), - additionalProperties.toMutableMap(), - ) + SessionEndResponse(success, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -134,7 +115,11 @@ private constructor( return@apply } - success().validate() + _success().let { + if (it != JsonValue.from(true)) { + throw StagehandInvalidDataException("'success' is invalid, received $it") + } + } validated = true } @@ -151,125 +136,8 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic internal fun validity(): Int = (success.asKnown().getOrNull()?.validity() ?: 0) - - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } + @JvmSynthetic + internal fun validity(): Int = success.let { if (it == JsonValue.from(true)) 1 else 0 } override fun equals(other: Any?): Boolean { if (this === other) { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt index 2478f77..8718994 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -24,14 +23,14 @@ class SessionExecuteResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val data: JsonField, - private val success: JsonField, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), ) : this(data, success, mutableMapOf()) /** @@ -41,10 +40,12 @@ private constructor( fun data(): Data = data.getRequired("data") /** + * Indicates whether the request was successful + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun success(): Success = success.getRequired("success") + fun success(): Boolean = success.getRequired("success") /** * Returns the raw JSON value of [data]. @@ -58,7 +59,7 @@ private constructor( * * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -90,7 +91,7 @@ private constructor( class Builder internal constructor() { private var data: JsonField? = null - private var success: JsonField? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -110,15 +111,16 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - fun success(success: Success) = success(JsonField.of(success)) + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) /** * Sets [Builder.success] to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -168,7 +170,7 @@ private constructor( } data().validate() - success().validate() + success() validated = true } @@ -187,8 +189,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + - (success.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -1637,124 +1638,6 @@ private constructor( override fun toString() = "Data{result=$result, additionalProperties=$additionalProperties}" } - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index f48f24f..e281560 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -22,14 +21,14 @@ class SessionExtractResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val data: JsonField, - private val success: JsonField, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), ) : this(data, success, mutableMapOf()) /** @@ -39,10 +38,12 @@ private constructor( fun data(): Data = data.getRequired("data") /** + * Indicates whether the request was successful + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun success(): Success = success.getRequired("success") + fun success(): Boolean = success.getRequired("success") /** * Returns the raw JSON value of [data]. @@ -56,7 +57,7 @@ private constructor( * * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -88,7 +89,7 @@ private constructor( class Builder internal constructor() { private var data: JsonField? = null - private var success: JsonField? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -108,15 +109,16 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - fun success(success: Success) = success(JsonField.of(success)) + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) /** * Sets [Builder.success] to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -166,7 +168,7 @@ private constructor( } data().validate() - success().validate() + success() validated = true } @@ -185,8 +187,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + - (success.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -355,124 +356,6 @@ private constructor( "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" } - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt index 56a53a4..2518477 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -22,14 +21,14 @@ class SessionNavigateResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val data: JsonField, - private val success: JsonField, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), ) : this(data, success, mutableMapOf()) /** @@ -39,10 +38,12 @@ private constructor( fun data(): Data = data.getRequired("data") /** + * Indicates whether the request was successful + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun success(): Success = success.getRequired("success") + fun success(): Boolean = success.getRequired("success") /** * Returns the raw JSON value of [data]. @@ -56,7 +57,7 @@ private constructor( * * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -88,7 +89,7 @@ private constructor( class Builder internal constructor() { private var data: JsonField? = null - private var success: JsonField? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -108,15 +109,16 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - fun success(success: Success) = success(JsonField.of(success)) + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) /** * Sets [Builder.success] to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -166,7 +168,7 @@ private constructor( } data().validate() - success().validate() + success() validated = true } @@ -185,8 +187,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + - (success.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -355,124 +356,6 @@ private constructor( "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" } - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt index a06fd48..cb2404e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -24,14 +23,14 @@ class SessionObserveResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val data: JsonField, - private val success: JsonField, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), ) : this(data, success, mutableMapOf()) /** @@ -41,10 +40,12 @@ private constructor( fun data(): Data = data.getRequired("data") /** + * Indicates whether the request was successful + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun success(): Success = success.getRequired("success") + fun success(): Boolean = success.getRequired("success") /** * Returns the raw JSON value of [data]. @@ -58,7 +59,7 @@ private constructor( * * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -90,7 +91,7 @@ private constructor( class Builder internal constructor() { private var data: JsonField? = null - private var success: JsonField? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -110,15 +111,16 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - fun success(success: Success) = success(JsonField.of(success)) + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) /** * Sets [Builder.success] to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -168,7 +170,7 @@ private constructor( } data().validate() - success().validate() + success() validated = true } @@ -187,8 +189,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + - (success.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -399,124 +400,6 @@ private constructor( "Data{result=$result, actionId=$actionId, additionalProperties=$additionalProperties}" } - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 20ba71d..59c94ad 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -142,7 +142,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun verbose(): Optional = body.verbose() + fun verbose(): Optional = body.verbose() /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -229,7 +229,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - fun _verbose(): JsonField = body._verbose() + fun _verbose(): JsonField = body._verbose() /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -459,15 +459,15 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Verbose) = apply { body.verbose(verbose) } + fun verbose(verbose: Long) = apply { body.verbose(verbose) } /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. This + * You should usually call [Builder.verbose] with a well-typed [Long] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = apply { body.waitForCaptchaSolves(waitForCaptchaSolves) @@ -653,7 +653,7 @@ private constructor( private val experimental: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, - private val verbose: JsonField, + private val verbose: JsonField, private val waitForCaptchaSolves: JsonField, private val additionalProperties: MutableMap, ) { @@ -689,7 +689,7 @@ private constructor( @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), + @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), @JsonProperty("waitForCaptchaSolves") @ExcludeMissing waitForCaptchaSolves: JsonField = JsonMissing.of(), @@ -790,7 +790,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verbose(): Optional = verbose.getOptional("verbose") + fun verbose(): Optional = verbose.getOptional("verbose") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if @@ -893,7 +893,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose + @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -944,7 +944,7 @@ private constructor( private var experimental: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() - private var verbose: JsonField = JsonMissing.of() + private var verbose: JsonField = JsonMissing.of() private var waitForCaptchaSolves: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -1098,16 +1098,16 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Verbose) = verbose(JsonField.of(verbose)) + fun verbose(verbose: Long) = verbose(JsonField.of(verbose)) /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. + * You should usually call [Builder.verbose] with a well-typed [Long] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + fun verbose(verbose: JsonField) = apply { this.verbose = verbose } fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = waitForCaptchaSolves(JsonField.of(waitForCaptchaSolves)) @@ -1189,7 +1189,7 @@ private constructor( experimental() selfHeal() systemPrompt() - verbose().ifPresent { it.validate() } + verbose() waitForCaptchaSolves() validated = true } @@ -1220,7 +1220,7 @@ private constructor( (if (experimental.asKnown().isPresent) 1 else 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + - (verbose.asKnown().getOrNull()?.validity() ?: 0) + + (if (verbose.asKnown().isPresent) 1 else 0) + (if (waitForCaptchaSolves.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -6084,7 +6084,7 @@ private constructor( class BrowserbaseProxyConfig @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val type: JsonField, + private val type: JsonValue, private val domainPattern: JsonField, private val geolocation: JsonField, private val additionalProperties: MutableMap, @@ -6092,9 +6092,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("type") - @ExcludeMissing - type: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), @JsonProperty("domainPattern") @ExcludeMissing domainPattern: JsonField = JsonMissing.of(), @@ -6104,11 +6102,15 @@ private constructor( ) : this(type, domainPattern, geolocation, mutableMapOf()) /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded with - * an unexpected value). + * Expected to always return the following: + * ```java + * JsonValue.from("browserbase") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the + * server responded with an unexpected value). */ - fun type(): Type = type.getRequired("type") + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** * @throws StagehandInvalidDataException if the JSON field has an unexpected @@ -6124,14 +6126,6 @@ private constructor( fun geolocation(): Optional = geolocation.getOptional("geolocation") - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - /** * Returns the raw JSON value of [domainPattern]. * @@ -6169,11 +6163,6 @@ private constructor( /** * Returns a mutable builder for constructing an instance of * [BrowserbaseProxyConfig]. - * - * The following fields are required: - * ```java - * .type() - * ``` */ @JvmStatic fun builder() = Builder() } @@ -6181,7 +6170,7 @@ private constructor( /** A builder for [BrowserbaseProxyConfig]. */ class Builder internal constructor() { - private var type: JsonField? = null + private var type: JsonValue = JsonValue.from("browserbase") private var domainPattern: JsonField = JsonMissing.of() private var geolocation: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = @@ -6196,16 +6185,19 @@ private constructor( browserbaseProxyConfig.additionalProperties.toMutableMap() } - fun type(type: Type) = type(JsonField.of(type)) - /** - * Sets [Builder.type] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. + * It is usually unnecessary to call this method because the field defaults + * to the following: + * ```java + * JsonValue.from("browserbase") + * ``` + * + * This method is primarily for setting the field to an undocumented or not + * yet supported value. */ - fun type(type: JsonField) = apply { this.type = type } + fun type(type: JsonValue) = apply { this.type = type } fun domainPattern(domainPattern: String) = domainPattern(JsonField.of(domainPattern)) @@ -6261,17 +6253,10 @@ private constructor( * Returns an immutable instance of [BrowserbaseProxyConfig]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .type() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): BrowserbaseProxyConfig = BrowserbaseProxyConfig( - checkRequired("type", type), + type, domainPattern, geolocation, additionalProperties.toMutableMap(), @@ -6285,7 +6270,13 @@ private constructor( return@apply } - type().validate() + _type().let { + if (it != JsonValue.from("browserbase")) { + throw StagehandInvalidDataException( + "'type' is invalid, received $it" + ) + } + } domainPattern() geolocation().ifPresent { it.validate() } validated = true @@ -6307,139 +6298,10 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (type.asKnown().getOrNull()?.validity() ?: 0) + + type.let { if (it == JsonValue.from("browserbase")) 1 else 0 } + (if (domainPattern.asKnown().isPresent) 1 else 0) + (geolocation.asKnown().getOrNull()?.validity() ?: 0) - class Type - @JsonCreator - private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data - * that doesn't match any known member, and you want to know that value. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val BROWSERBASE = of("browserbase") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - BROWSERBASE - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] - * member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API - * may respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - BROWSERBASE, - /** - * An enum member indicating that [Type] was instantiated with an - * unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always - * known or if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - BROWSERBASE -> Value.BROWSERBASE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always - * known and don't want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a - * not a known member. - */ - fun known(): Known = - when (this) { - BROWSERBASE -> Known.BROWSERBASE - else -> throw StagehandInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily - * for debugging and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does - * not have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - class Geolocation @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( @@ -6713,7 +6575,7 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val server: JsonField, - private val type: JsonField, + private val type: JsonValue, private val domainPattern: JsonField, private val password: JsonField, private val username: JsonField, @@ -6725,9 +6587,7 @@ private constructor( @JsonProperty("server") @ExcludeMissing server: JsonField = JsonMissing.of(), - @JsonProperty("type") - @ExcludeMissing - type: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), @JsonProperty("domainPattern") @ExcludeMissing domainPattern: JsonField = JsonMissing.of(), @@ -6747,11 +6607,15 @@ private constructor( fun server(): String = server.getRequired("server") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded with - * an unexpected value). + * Expected to always return the following: + * ```java + * JsonValue.from("external") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the + * server responded with an unexpected value). */ - fun type(): Type = type.getRequired("type") + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** * @throws StagehandInvalidDataException if the JSON field has an unexpected @@ -6782,14 +6646,6 @@ private constructor( @ExcludeMissing fun _server(): JsonField = server - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - /** * Returns the raw JSON value of [domainPattern]. * @@ -6841,7 +6697,6 @@ private constructor( * The following fields are required: * ```java * .server() - * .type() * ``` */ @JvmStatic fun builder() = Builder() @@ -6851,7 +6706,7 @@ private constructor( class Builder internal constructor() { private var server: JsonField? = null - private var type: JsonField? = null + private var type: JsonValue = JsonValue.from("external") private var domainPattern: JsonField = JsonMissing.of() private var password: JsonField = JsonMissing.of() private var username: JsonField = JsonMissing.of() @@ -6880,16 +6735,19 @@ private constructor( */ fun server(server: JsonField) = apply { this.server = server } - fun type(type: Type) = type(JsonField.of(type)) - /** - * Sets [Builder.type] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. + * It is usually unnecessary to call this method because the field defaults + * to the following: + * ```java + * JsonValue.from("external") + * ``` + * + * This method is primarily for setting the field to an undocumented or not + * yet supported value. */ - fun type(type: JsonField) = apply { this.type = type } + fun type(type: JsonValue) = apply { this.type = type } fun domainPattern(domainPattern: String) = domainPattern(JsonField.of(domainPattern)) @@ -6961,7 +6819,6 @@ private constructor( * The following fields are required: * ```java * .server() - * .type() * ``` * * @throws IllegalStateException if any required field is unset. @@ -6969,7 +6826,7 @@ private constructor( fun build(): ExternalProxyConfig = ExternalProxyConfig( checkRequired("server", server), - checkRequired("type", type), + type, domainPattern, password, username, @@ -6985,7 +6842,13 @@ private constructor( } server() - type().validate() + _type().let { + if (it != JsonValue.from("external")) { + throw StagehandInvalidDataException( + "'type' is invalid, received $it" + ) + } + } domainPattern() password() username() @@ -7009,140 +6872,11 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (server.asKnown().isPresent) 1 else 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) + + type.let { if (it == JsonValue.from("external")) 1 else 0 } + (if (domainPattern.asKnown().isPresent) 1 else 0) + (if (password.asKnown().isPresent) 1 else 0) + (if (username.asKnown().isPresent) 1 else 0) - class Type - @JsonCreator - private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data - * that doesn't match any known member, and you want to know that value. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val EXTERNAL = of("external") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - EXTERNAL - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] - * member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API - * may respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - EXTERNAL, - /** - * An enum member indicating that [Type] was instantiated with an - * unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always - * known or if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - EXTERNAL -> Value.EXTERNAL - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always - * known and don't want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a - * not a known member. - */ - fun known(): Known = - when (this) { - EXTERNAL -> Known.EXTERNAL - else -> throw StagehandInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily - * for debugging and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does - * not have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Type && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -7456,136 +7190,6 @@ private constructor( "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" } - /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val _0 = of(0.0) - - @JvmField val _1 = of(1.0) - - @JvmField val _2 = of(2.0) - - @JvmStatic fun of(value: Double) = Verbose(JsonField.of(value)) - } - - /** An enum containing [Verbose]'s known values. */ - enum class Known { - _0, - _1, - _2, - } - - /** - * An enum containing [Verbose]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Verbose] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - _0, - _1, - _2, - /** An enum member indicating that [Verbose] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - _0 -> Value._0 - _1 -> Value._1 - _2 -> Value._2 - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - _0 -> Known._0 - _1 -> Known._1 - _2 -> Known._2 - else -> throw StagehandInvalidDataException("Unknown Verbose: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asDouble(): Double = - _value().asNumber().getOrNull()?.toDouble() - ?: throw StagehandInvalidDataException("Value is not a Double") - - private var validated: Boolean = false - - fun validate(): Verbose = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Verbose && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Client SDK language */ class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index 420925f..a172070 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -21,14 +20,14 @@ class SessionStartResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val data: JsonField, - private val success: JsonField, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), - @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), ) : this(data, success, mutableMapOf()) /** @@ -38,10 +37,12 @@ private constructor( fun data(): Data = data.getRequired("data") /** + * Indicates whether the request was successful + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun success(): Success = success.getRequired("success") + fun success(): Boolean = success.getRequired("success") /** * Returns the raw JSON value of [data]. @@ -55,7 +56,7 @@ private constructor( * * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -87,7 +88,7 @@ private constructor( class Builder internal constructor() { private var data: JsonField? = null - private var success: JsonField? = null + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -107,15 +108,16 @@ private constructor( */ fun data(data: JsonField) = apply { this.data = data } - fun success(success: Success) = success(JsonField.of(success)) + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) /** * Sets [Builder.success] to an arbitrary JSON value. * - * You should usually call [Builder.success] with a well-typed [Success] value instead. This + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonField) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -165,7 +167,7 @@ private constructor( } data().validate() - success().validate() + success() validated = true } @@ -184,8 +186,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (data.asKnown().getOrNull()?.validity() ?: 0) + - (success.asKnown().getOrNull()?.validity() ?: 0) + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -388,124 +389,6 @@ private constructor( "Data{available=$available, sessionId=$sessionId, additionalProperties=$additionalProperties}" } - class Success @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TRUE = of(true) - - @JvmStatic fun of(value: Boolean) = Success(JsonField.of(value)) - } - - /** An enum containing [Success]'s known values. */ - enum class Known { - TRUE - } - - /** - * An enum containing [Success]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Success] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TRUE, - /** An enum member indicating that [Success] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TRUE -> Value.TRUE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TRUE -> Known.TRUE - else -> throw StagehandInvalidDataException("Unknown Success: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asBoolean(): Boolean = - _value().asBoolean().orElseThrow { - StagehandInvalidDataException("Value is not a Boolean") - } - - private var validated: Boolean = false - - fun validate(): Success = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Success && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt index 000d7fd..f5e0363 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt @@ -33,7 +33,7 @@ internal class SessionActResponseTest { .actionId("actionId") .build() ) - .success(SessionActResponse.Success.TRUE) + .success(true) .build() assertThat(sessionActResponse.data()) @@ -57,7 +57,7 @@ internal class SessionActResponseTest { .actionId("actionId") .build() ) - assertThat(sessionActResponse.success()).isEqualTo(SessionActResponse.Success.TRUE) + assertThat(sessionActResponse.success()).isEqualTo(true) } @Test @@ -85,7 +85,7 @@ internal class SessionActResponseTest { .actionId("actionId") .build() ) - .success(SessionActResponse.Success.TRUE) + .success(true) .build() val roundtrippedSessionActResponse = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt index 27a2a36..30e45db 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt @@ -11,17 +11,13 @@ internal class SessionEndResponseTest { @Test fun create() { - val sessionEndResponse = - SessionEndResponse.builder().success(SessionEndResponse.Success.TRUE).build() - - assertThat(sessionEndResponse.success()).isEqualTo(SessionEndResponse.Success.TRUE) + val sessionEndResponse = SessionEndResponse.builder().build() } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionEndResponse = - SessionEndResponse.builder().success(SessionEndResponse.Success.TRUE).build() + val sessionEndResponse = SessionEndResponse.builder().build() val roundtrippedSessionEndResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt index d2fb4d9..85a2099 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt @@ -51,7 +51,7 @@ internal class SessionExecuteResponseTest { ) .build() ) - .success(SessionExecuteResponse.Success.TRUE) + .success(true) .build() assertThat(sessionExecuteResponse.data()) @@ -92,7 +92,7 @@ internal class SessionExecuteResponseTest { ) .build() ) - assertThat(sessionExecuteResponse.success()).isEqualTo(SessionExecuteResponse.Success.TRUE) + assertThat(sessionExecuteResponse.success()).isEqualTo(true) } @Test @@ -137,7 +137,7 @@ internal class SessionExecuteResponseTest { ) .build() ) - .success(SessionExecuteResponse.Success.TRUE) + .success(true) .build() val roundtrippedSessionExecuteResponse = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt index 6cf7056..3f055cd 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractResponseTest.kt @@ -20,7 +20,7 @@ internal class SessionExtractResponseTest { .actionId("actionId") .build() ) - .success(SessionExtractResponse.Success.TRUE) + .success(true) .build() assertThat(sessionExtractResponse.data()) @@ -30,7 +30,7 @@ internal class SessionExtractResponseTest { .actionId("actionId") .build() ) - assertThat(sessionExtractResponse.success()).isEqualTo(SessionExtractResponse.Success.TRUE) + assertThat(sessionExtractResponse.success()).isEqualTo(true) } @Test @@ -44,7 +44,7 @@ internal class SessionExtractResponseTest { .actionId("actionId") .build() ) - .success(SessionExtractResponse.Success.TRUE) + .success(true) .build() val roundtrippedSessionExtractResponse = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt index e02a0e3..bca29d9 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponseTest.kt @@ -20,7 +20,7 @@ internal class SessionNavigateResponseTest { .actionId("actionId") .build() ) - .success(SessionNavigateResponse.Success.TRUE) + .success(true) .build() assertThat(sessionNavigateResponse.data()) @@ -30,8 +30,7 @@ internal class SessionNavigateResponseTest { .actionId("actionId") .build() ) - assertThat(sessionNavigateResponse.success()) - .isEqualTo(SessionNavigateResponse.Success.TRUE) + assertThat(sessionNavigateResponse.success()).isEqualTo(true) } @Test @@ -45,7 +44,7 @@ internal class SessionNavigateResponseTest { .actionId("actionId") .build() ) - .success(SessionNavigateResponse.Success.TRUE) + .success(true) .build() val roundtrippedSessionNavigateResponse = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt index e3d72c3..2cc31b8 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt @@ -26,7 +26,7 @@ internal class SessionObserveResponseTest { .actionId("actionId") .build() ) - .success(SessionObserveResponse.Success.TRUE) + .success(true) .build() assertThat(sessionObserveResponse.data()) @@ -43,7 +43,7 @@ internal class SessionObserveResponseTest { .actionId("actionId") .build() ) - assertThat(sessionObserveResponse.success()).isEqualTo(SessionObserveResponse.Success.TRUE) + assertThat(sessionObserveResponse.success()).isEqualTo(true) } @Test @@ -64,7 +64,7 @@ internal class SessionObserveResponseTest { .actionId("actionId") .build() ) - .success(SessionObserveResponse.Success.TRUE) + .success(true) .build() val roundtrippedSessionObserveResponse = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 13ae538..0dc5811 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -153,7 +153,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() } @@ -306,7 +306,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() @@ -480,7 +480,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() @@ -624,7 +624,7 @@ internal class SessionStartParamsTest { assertThat(body.experimental()).contains(true) assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") - assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) + assertThat(body.verbose()).contains(1L) assertThat(body.waitForCaptchaSolves()).contains(true) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt index 717d6d6..3af1696 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt @@ -19,7 +19,7 @@ internal class SessionStartResponseTest { .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .build() ) - .success(SessionStartResponse.Success.TRUE) + .success(true) .build() assertThat(sessionStartResponse.data()) @@ -29,7 +29,7 @@ internal class SessionStartResponseTest { .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .build() ) - assertThat(sessionStartResponse.success()).isEqualTo(SessionStartResponse.Success.TRUE) + assertThat(sessionStartResponse.success()).isEqualTo(true) } @Test @@ -43,7 +43,7 @@ internal class SessionStartResponseTest { .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .build() ) - .success(SessionStartResponse.Success.TRUE) + .success(true) .build() val roundtrippedSessionStartResponse = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 87af3f1..967794c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -230,7 +230,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -410,7 +410,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -590,7 +590,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -770,7 +770,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -950,7 +950,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1130,7 +1130,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1310,7 +1310,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1490,7 +1490,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1670,7 +1670,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1850,7 +1850,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2030,7 +2030,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2210,7 +2210,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2390,7 +2390,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2570,7 +2570,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2750,7 +2750,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2930,7 +2930,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -3108,7 +3108,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index ecf30b0..beb2b92 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -192,7 +192,7 @@ internal class ServiceParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 0011f6f..fd11f6e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -406,7 +406,7 @@ internal class SessionServiceAsyncTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 3f62ca6..ba02cd0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -400,7 +400,7 @@ internal class SessionServiceTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) From 240da407d205d49c150d3d22c7e0cf8f00b23e32 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:56:01 +0000 Subject: [PATCH 034/164] feat(api): manual updates --- .stats.yml | 4 +- .../api/models/sessions/ModelConfig.kt | 116 +++--- .../api/models/sessions/SessionActParams.kt | 19 +- .../api/models/sessions/SessionEndResponse.kt | 73 ++-- .../models/sessions/SessionExecuteParams.kt | 19 +- .../models/sessions/SessionExtractParams.kt | 19 +- .../models/sessions/SessionObserveParams.kt | 19 +- .../api/models/sessions/SessionStartParams.kt | 352 +++++++++++------- .../api/models/sessions/ModelConfigTest.kt | 44 +-- .../models/sessions/SessionActParamsTest.kt | 8 +- .../models/sessions/SessionEndResponseTest.kt | 6 +- .../sessions/SessionExecuteParamsTest.kt | 8 +- .../sessions/SessionExtractParamsTest.kt | 8 +- .../sessions/SessionObserveParamsTest.kt | 8 +- .../models/sessions/SessionStartParamsTest.kt | 8 +- .../api/services/ErrorHandlingTest.kt | 34 +- .../api/services/ServiceParamsTest.kt | 4 +- .../services/async/SessionServiceAsyncTest.kt | 10 +- .../services/blocking/SessionServiceTest.kt | 10 +- .../api/proguard/ProGuardCompatibilityTest.kt | 2 +- 20 files changed, 473 insertions(+), 298 deletions(-) diff --git a/.stats.yml b/.stats.yml index 08f0cef..38ef77c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-d571232203ef4e00986a3245224267db6f8aaffdad57780f712e0694dc8d9e37.yml -openapi_spec_hash: d5d635dd7b24a2e1255c6f2a895253ff +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-817d1d4e845b1946dac8ee10fd34b3f533aa36f74ac598582ffb1b0399a5a932.yml +openapi_spec_hash: 9d856db62b34909fec94743235b3d7be config_hash: 88e87ba7021be93d267ecfc8f5e6b891 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 0d210b0..e416a06 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -27,33 +27,44 @@ import java.util.Collections import java.util.Objects import java.util.Optional +/** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') + */ @JsonDeserialize(using = ModelConfig.Deserializer::class) @JsonSerialize(using = ModelConfig.Serializer::class) class ModelConfig private constructor( - private val string: String? = null, - private val unionMember1: UnionMember1? = null, + private val name: String? = null, + private val modelConfigObject: ModelConfigObject? = null, private val _json: JsonValue? = null, ) { - fun string(): Optional = Optional.ofNullable(string) + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ + fun name(): Optional = Optional.ofNullable(name) - fun unionMember1(): Optional = Optional.ofNullable(unionMember1) + fun modelConfigObject(): Optional = Optional.ofNullable(modelConfigObject) - fun isString(): Boolean = string != null + fun isName(): Boolean = name != null - fun isUnionMember1(): Boolean = unionMember1 != null + fun isModelConfigObject(): Boolean = modelConfigObject != null - fun asString(): String = string.getOrThrow("string") + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ + fun asName(): String = name.getOrThrow("name") - fun asUnionMember1(): UnionMember1 = unionMember1.getOrThrow("unionMember1") + fun asModelConfigObject(): ModelConfigObject = modelConfigObject.getOrThrow("modelConfigObject") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { - string != null -> visitor.visitString(string) - unionMember1 != null -> visitor.visitUnionMember1(unionMember1) + name != null -> visitor.visitName(name) + modelConfigObject != null -> visitor.visitModelConfigObject(modelConfigObject) else -> visitor.unknown(_json) } @@ -66,10 +77,10 @@ private constructor( accept( object : Visitor { - override fun visitString(string: String) {} + override fun visitName(name: String) {} - override fun visitUnionMember1(unionMember1: UnionMember1) { - unionMember1.validate() + override fun visitModelConfigObject(modelConfigObject: ModelConfigObject) { + modelConfigObject.validate() } } ) @@ -93,9 +104,10 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitString(string: String) = 1 + override fun visitName(name: String) = 1 - override fun visitUnionMember1(unionMember1: UnionMember1) = unionMember1.validity() + override fun visitModelConfigObject(modelConfigObject: ModelConfigObject) = + modelConfigObject.validity() override fun unknown(json: JsonValue?) = 0 } @@ -106,25 +118,32 @@ private constructor( return true } - return other is ModelConfig && string == other.string && unionMember1 == other.unionMember1 + return other is ModelConfig && + name == other.name && + modelConfigObject == other.modelConfigObject } - override fun hashCode(): Int = Objects.hash(string, unionMember1) + override fun hashCode(): Int = Objects.hash(name, modelConfigObject) override fun toString(): String = when { - string != null -> "ModelConfig{string=$string}" - unionMember1 != null -> "ModelConfig{unionMember1=$unionMember1}" + name != null -> "ModelConfig{name=$name}" + modelConfigObject != null -> "ModelConfig{modelConfigObject=$modelConfigObject}" _json != null -> "ModelConfig{_unknown=$_json}" else -> throw IllegalStateException("Invalid ModelConfig") } companion object { - @JvmStatic fun ofString(string: String) = ModelConfig(string = string) + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ + @JvmStatic fun ofName(name: String) = ModelConfig(name = name) @JvmStatic - fun ofUnionMember1(unionMember1: UnionMember1) = ModelConfig(unionMember1 = unionMember1) + fun ofModelConfigObject(modelConfigObject: ModelConfigObject) = + ModelConfig(modelConfigObject = modelConfigObject) } /** @@ -132,9 +151,13 @@ private constructor( */ interface Visitor { - fun visitString(string: String): T + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ + fun visitName(name: String): T - fun visitUnionMember1(unionMember1: UnionMember1): T + fun visitModelConfigObject(modelConfigObject: ModelConfigObject): T /** * Maps an unknown variant of [ModelConfig] to a value of type [T]. @@ -157,11 +180,11 @@ private constructor( val bestMatches = sequenceOf( - tryDeserialize(node, jacksonTypeRef())?.let { - ModelConfig(unionMember1 = it, _json = json) + tryDeserialize(node, jacksonTypeRef())?.let { + ModelConfig(modelConfigObject = it, _json = json) }, tryDeserialize(node, jacksonTypeRef())?.let { - ModelConfig(string = it, _json = json) + ModelConfig(name = it, _json = json) }, ) .filterNotNull() @@ -187,15 +210,15 @@ private constructor( provider: SerializerProvider, ) { when { - value.string != null -> generator.writeObject(value.string) - value.unionMember1 != null -> generator.writeObject(value.unionMember1) + value.name != null -> generator.writeObject(value.name) + value.modelConfigObject != null -> generator.writeObject(value.modelConfigObject) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid ModelConfig") } } } - class UnionMember1 + class ModelConfigObject @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val modelName: JsonField, @@ -214,18 +237,24 @@ private constructor( ) : this(modelName, apiKey, baseUrl, mutableMapOf()) /** + * Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ fun modelName(): String = modelName.getRequired("modelName") /** + * API key for the model provider + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun apiKey(): Optional = apiKey.getOptional("apiKey") /** + * Base URL for the model provider + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -267,7 +296,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [UnionMember1]. + * Returns a mutable builder for constructing an instance of [ModelConfigObject]. * * The following fields are required: * ```java @@ -277,7 +306,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [UnionMember1]. */ + /** A builder for [ModelConfigObject]. */ class Builder internal constructor() { private var modelName: JsonField? = null @@ -286,13 +315,14 @@ private constructor( private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(unionMember1: UnionMember1) = apply { - modelName = unionMember1.modelName - apiKey = unionMember1.apiKey - baseUrl = unionMember1.baseUrl - additionalProperties = unionMember1.additionalProperties.toMutableMap() + internal fun from(modelConfigObject: ModelConfigObject) = apply { + modelName = modelConfigObject.modelName + apiKey = modelConfigObject.apiKey + baseUrl = modelConfigObject.baseUrl + additionalProperties = modelConfigObject.additionalProperties.toMutableMap() } + /** Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus') */ fun modelName(modelName: String) = modelName(JsonField.of(modelName)) /** @@ -304,6 +334,7 @@ private constructor( */ fun modelName(modelName: JsonField) = apply { this.modelName = modelName } + /** API key for the model provider */ fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) /** @@ -315,6 +346,7 @@ private constructor( */ fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + /** Base URL for the model provider */ fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) /** @@ -346,7 +378,7 @@ private constructor( } /** - * Returns an immutable instance of [UnionMember1]. + * Returns an immutable instance of [ModelConfigObject]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -357,8 +389,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): UnionMember1 = - UnionMember1( + fun build(): ModelConfigObject = + ModelConfigObject( checkRequired("modelName", modelName), apiKey, baseUrl, @@ -368,7 +400,7 @@ private constructor( private var validated: Boolean = false - fun validate(): UnionMember1 = apply { + fun validate(): ModelConfigObject = apply { if (validated) { return@apply } @@ -404,7 +436,7 @@ private constructor( return true } - return other is UnionMember1 && + return other is ModelConfigObject && modelName == other.modelName && apiKey == other.apiKey && baseUrl == other.baseUrl && @@ -418,6 +450,6 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "UnionMember1{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, additionalProperties=$additionalProperties}" + "ModelConfigObject{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, additionalProperties=$additionalProperties}" } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 7e98b5d..019f026 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -1133,6 +1133,9 @@ private constructor( ) : this(model, timeout, variables, mutableMapOf()) /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -1211,6 +1214,10 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -1222,12 +1229,14 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) + /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ + fun model(name: String) = model(ModelConfig.ofName(name)) - /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ - fun model(unionMember1: ModelConfig.UnionMember1) = - model(ModelConfig.ofUnionMember1(unionMember1)) + /** + * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. + */ + fun model(modelConfigObject: ModelConfig.ModelConfigObject) = + model(ModelConfig.ofModelConfigObject(modelConfigObject)) /** Timeout in ms for the action */ fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt index 3345222..3a886e7 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -3,8 +3,10 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -16,25 +18,29 @@ import java.util.Objects class SessionEndResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val success: JsonValue, + private val success: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("success") @ExcludeMissing success: JsonValue = JsonMissing.of() + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of() ) : this(success, mutableMapOf()) /** - * Expected to always return the following: - * ```java - * JsonValue.from(true) - * ``` + * Indicates whether the request was successful * - * However, this method can be useful for debugging and logging (e.g. if the server responded - * with an unexpected value). + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - @JsonProperty("success") @ExcludeMissing fun _success(): JsonValue = success + fun success(): Boolean = success.getRequired("success") + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -50,14 +56,21 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [SessionEndResponse]. */ + /** + * Returns a mutable builder for constructing an instance of [SessionEndResponse]. + * + * The following fields are required: + * ```java + * .success() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [SessionEndResponse]. */ class Builder internal constructor() { - private var success: JsonValue = JsonValue.from(true) + private var success: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -66,19 +79,16 @@ private constructor( additionalProperties = sessionEndResponse.additionalProperties.toMutableMap() } + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) + /** - * Sets the field to an arbitrary JSON value. + * Sets [Builder.success] to an arbitrary JSON value. * - * It is usually unnecessary to call this method because the field defaults to the - * following: - * ```java - * JsonValue.from(true) - * ``` - * - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun success(success: JsonValue) = apply { this.success = success } + fun success(success: JsonField) = apply { this.success = success } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -103,9 +113,19 @@ private constructor( * Returns an immutable instance of [SessionEndResponse]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .success() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): SessionEndResponse = - SessionEndResponse(success, additionalProperties.toMutableMap()) + SessionEndResponse( + checkRequired("success", success), + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -115,11 +135,7 @@ private constructor( return@apply } - _success().let { - if (it != JsonValue.from(true)) { - throw StagehandInvalidDataException("'success' is invalid, received $it") - } - } + success() validated = true } @@ -136,8 +152,7 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic - internal fun validity(): Int = success.let { if (it == JsonValue.from(true)) 1 else 0 } + @JvmSynthetic internal fun validity(): Int = (if (success.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 4b615cf..73880ff 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -657,6 +657,9 @@ private constructor( fun cua(): Optional = cua.getOptional("cua") /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -740,6 +743,10 @@ private constructor( */ fun cua(cua: JsonField) = apply { this.cua = cua } + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -751,12 +758,14 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) + /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ + fun model(name: String) = model(ModelConfig.ofName(name)) - /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ - fun model(unionMember1: ModelConfig.UnionMember1) = - model(ModelConfig.ofUnionMember1(unionMember1)) + /** + * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. + */ + fun model(modelConfigObject: ModelConfig.ModelConfigObject) = + model(ModelConfig.ofModelConfigObject(modelConfigObject)) /** Custom system prompt for the agent */ fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index b86cdc3..3a5c4bd 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -666,6 +666,9 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -742,6 +745,10 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -753,12 +760,14 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) + /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ + fun model(name: String) = model(ModelConfig.ofName(name)) - /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ - fun model(unionMember1: ModelConfig.UnionMember1) = - model(ModelConfig.ofUnionMember1(unionMember1)) + /** + * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. + */ + fun model(modelConfigObject: ModelConfig.ModelConfigObject) = + model(ModelConfig.ofModelConfigObject(modelConfigObject)) /** CSS selector to scope extraction to a specific element */ fun selector(selector: String) = selector(JsonField.of(selector)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 7e40f70..66c3b91 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -606,6 +606,9 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -682,6 +685,10 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } + /** + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', + * 'anthropic/claude-4.5-opus') + */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -693,12 +700,14 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) + /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ + fun model(name: String) = model(ModelConfig.ofName(name)) - /** Alias for calling [model] with `ModelConfig.ofUnionMember1(unionMember1)`. */ - fun model(unionMember1: ModelConfig.UnionMember1) = - model(ModelConfig.ofUnionMember1(unionMember1)) + /** + * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. + */ + fun model(modelConfigObject: ModelConfig.ModelConfigObject) = + model(ModelConfig.ofModelConfigObject(modelConfigObject)) /** CSS selector to scope observation to a specific element */ fun selector(selector: String) = selector(JsonField.of(selector)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 59c94ad..57f072f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -142,7 +142,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun verbose(): Optional = body.verbose() + fun verbose(): Optional = body.verbose() /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -229,7 +229,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - fun _verbose(): JsonField = body._verbose() + fun _verbose(): JsonField = body._verbose() /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -459,15 +459,15 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Long) = apply { body.verbose(verbose) } + fun verbose(verbose: Verbose) = apply { body.verbose(verbose) } /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Long] value instead. This + * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = apply { body.waitForCaptchaSolves(waitForCaptchaSolves) @@ -653,7 +653,7 @@ private constructor( private val experimental: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, - private val verbose: JsonField, + private val verbose: JsonField, private val waitForCaptchaSolves: JsonField, private val additionalProperties: MutableMap, ) { @@ -689,7 +689,7 @@ private constructor( @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), + @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), @JsonProperty("waitForCaptchaSolves") @ExcludeMissing waitForCaptchaSolves: JsonField = JsonMissing.of(), @@ -790,7 +790,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verbose(): Optional = verbose.getOptional("verbose") + fun verbose(): Optional = verbose.getOptional("verbose") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if @@ -893,7 +893,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose + @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -944,7 +944,7 @@ private constructor( private var experimental: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() - private var verbose: JsonField = JsonMissing.of() + private var verbose: JsonField = JsonMissing.of() private var waitForCaptchaSolves: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -1098,16 +1098,16 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Long) = verbose(JsonField.of(verbose)) + fun verbose(verbose: Verbose) = verbose(JsonField.of(verbose)) /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Long] value instead. + * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + fun verbose(verbose: JsonField) = apply { this.verbose = verbose } fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = waitForCaptchaSolves(JsonField.of(waitForCaptchaSolves)) @@ -1189,7 +1189,7 @@ private constructor( experimental() selfHeal() systemPrompt() - verbose() + verbose().ifPresent { it.validate() } waitForCaptchaSolves() validated = true } @@ -1220,7 +1220,7 @@ private constructor( (if (experimental.asKnown().isPresent) 1 else 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + - (if (verbose.asKnown().isPresent) 1 else 0) + + (verbose.asKnown().getOrNull()?.validity() ?: 0) + (if (waitForCaptchaSolves.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -5862,35 +5862,29 @@ private constructor( @JsonSerialize(using = UnnamedSchemaWithArrayParent0.Serializer::class) class UnnamedSchemaWithArrayParent0 private constructor( - private val browserbaseProxyConfig: BrowserbaseProxyConfig? = null, - private val externalProxyConfig: ExternalProxyConfig? = null, + private val browserbase: Browserbase? = null, + private val external: External? = null, private val _json: JsonValue? = null, ) { - fun browserbaseProxyConfig(): Optional = - Optional.ofNullable(browserbaseProxyConfig) + fun browserbase(): Optional = Optional.ofNullable(browserbase) - fun externalProxyConfig(): Optional = - Optional.ofNullable(externalProxyConfig) + fun external(): Optional = Optional.ofNullable(external) - fun isBrowserbaseProxyConfig(): Boolean = browserbaseProxyConfig != null + fun isBrowserbase(): Boolean = browserbase != null - fun isExternalProxyConfig(): Boolean = externalProxyConfig != null + fun isExternal(): Boolean = external != null - fun asBrowserbaseProxyConfig(): BrowserbaseProxyConfig = - browserbaseProxyConfig.getOrThrow("browserbaseProxyConfig") + fun asBrowserbase(): Browserbase = browserbase.getOrThrow("browserbase") - fun asExternalProxyConfig(): ExternalProxyConfig = - externalProxyConfig.getOrThrow("externalProxyConfig") + fun asExternal(): External = external.getOrThrow("external") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { - browserbaseProxyConfig != null -> - visitor.visitBrowserbaseProxyConfig(browserbaseProxyConfig) - externalProxyConfig != null -> - visitor.visitExternalProxyConfig(externalProxyConfig) + browserbase != null -> visitor.visitBrowserbase(browserbase) + external != null -> visitor.visitExternal(external) else -> visitor.unknown(_json) } @@ -5903,16 +5897,12 @@ private constructor( accept( object : Visitor { - override fun visitBrowserbaseProxyConfig( - browserbaseProxyConfig: BrowserbaseProxyConfig - ) { - browserbaseProxyConfig.validate() + override fun visitBrowserbase(browserbase: Browserbase) { + browserbase.validate() } - override fun visitExternalProxyConfig( - externalProxyConfig: ExternalProxyConfig - ) { - externalProxyConfig.validate() + override fun visitExternal(external: External) { + external.validate() } } ) @@ -5937,13 +5927,10 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitBrowserbaseProxyConfig( - browserbaseProxyConfig: BrowserbaseProxyConfig - ) = browserbaseProxyConfig.validity() + override fun visitBrowserbase(browserbase: Browserbase) = + browserbase.validity() - override fun visitExternalProxyConfig( - externalProxyConfig: ExternalProxyConfig - ) = externalProxyConfig.validity() + override fun visitExternal(external: External) = external.validity() override fun unknown(json: JsonValue?) = 0 } @@ -5955,19 +5942,17 @@ private constructor( } return other is UnnamedSchemaWithArrayParent0 && - browserbaseProxyConfig == other.browserbaseProxyConfig && - externalProxyConfig == other.externalProxyConfig + browserbase == other.browserbase && + external == other.external } - override fun hashCode(): Int = - Objects.hash(browserbaseProxyConfig, externalProxyConfig) + override fun hashCode(): Int = Objects.hash(browserbase, external) override fun toString(): String = when { - browserbaseProxyConfig != null -> - "UnnamedSchemaWithArrayParent0{browserbaseProxyConfig=$browserbaseProxyConfig}" - externalProxyConfig != null -> - "UnnamedSchemaWithArrayParent0{externalProxyConfig=$externalProxyConfig}" + browserbase != null -> + "UnnamedSchemaWithArrayParent0{browserbase=$browserbase}" + external != null -> "UnnamedSchemaWithArrayParent0{external=$external}" _json != null -> "UnnamedSchemaWithArrayParent0{_unknown=$_json}" else -> throw IllegalStateException("Invalid UnnamedSchemaWithArrayParent0") } @@ -5975,14 +5960,12 @@ private constructor( companion object { @JvmStatic - fun ofBrowserbaseProxyConfig(browserbaseProxyConfig: BrowserbaseProxyConfig) = - UnnamedSchemaWithArrayParent0( - browserbaseProxyConfig = browserbaseProxyConfig - ) + fun ofBrowserbase(browserbase: Browserbase) = + UnnamedSchemaWithArrayParent0(browserbase = browserbase) @JvmStatic - fun ofExternalProxyConfig(externalProxyConfig: ExternalProxyConfig) = - UnnamedSchemaWithArrayParent0(externalProxyConfig = externalProxyConfig) + fun ofExternal(external: External) = + UnnamedSchemaWithArrayParent0(external = external) } /** @@ -5991,11 +5974,9 @@ private constructor( */ interface Visitor { - fun visitBrowserbaseProxyConfig( - browserbaseProxyConfig: BrowserbaseProxyConfig - ): T + fun visitBrowserbase(browserbase: Browserbase): T - fun visitExternalProxyConfig(externalProxyConfig: ExternalProxyConfig): T + fun visitExternal(external: External): T /** * Maps an unknown variant of [UnnamedSchemaWithArrayParent0] to a value of type @@ -6024,38 +6005,22 @@ private constructor( node: JsonNode ): UnnamedSchemaWithArrayParent0 { val json = JsonValue.fromJsonNode(node) + val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { - UnnamedSchemaWithArrayParent0( - browserbaseProxyConfig = it, - _json = json, - ) - }, - tryDeserialize(node, jacksonTypeRef()) - ?.let { - UnnamedSchemaWithArrayParent0( - externalProxyConfig = it, - _json = json, - ) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing from - // boolean). - 0 -> UnnamedSchemaWithArrayParent0(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use - // the first completely valid match, or simply the first match if none - // are completely valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + when (type) { + "browserbase" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + UnnamedSchemaWithArrayParent0(browserbase = it, _json = json) + } ?: UnnamedSchemaWithArrayParent0(_json = json) + } + "external" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + UnnamedSchemaWithArrayParent0(external = it, _json = json) + } ?: UnnamedSchemaWithArrayParent0(_json = json) + } } + + return UnnamedSchemaWithArrayParent0(_json = json) } } @@ -6070,10 +6035,8 @@ private constructor( provider: SerializerProvider, ) { when { - value.browserbaseProxyConfig != null -> - generator.writeObject(value.browserbaseProxyConfig) - value.externalProxyConfig != null -> - generator.writeObject(value.externalProxyConfig) + value.browserbase != null -> generator.writeObject(value.browserbase) + value.external != null -> generator.writeObject(value.external) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid UnnamedSchemaWithArrayParent0") @@ -6081,7 +6044,7 @@ private constructor( } } - class BrowserbaseProxyConfig + class Browserbase @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val type: JsonValue, @@ -6161,13 +6124,12 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [BrowserbaseProxyConfig]. + * Returns a mutable builder for constructing an instance of [Browserbase]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [BrowserbaseProxyConfig]. */ + /** A builder for [Browserbase]. */ class Builder internal constructor() { private var type: JsonValue = JsonValue.from("browserbase") @@ -6177,12 +6139,11 @@ private constructor( mutableMapOf() @JvmSynthetic - internal fun from(browserbaseProxyConfig: BrowserbaseProxyConfig) = apply { - type = browserbaseProxyConfig.type - domainPattern = browserbaseProxyConfig.domainPattern - geolocation = browserbaseProxyConfig.geolocation - additionalProperties = - browserbaseProxyConfig.additionalProperties.toMutableMap() + internal fun from(browserbase: Browserbase) = apply { + type = browserbase.type + domainPattern = browserbase.domainPattern + geolocation = browserbase.geolocation + additionalProperties = browserbase.additionalProperties.toMutableMap() } /** @@ -6250,12 +6211,12 @@ private constructor( } /** - * Returns an immutable instance of [BrowserbaseProxyConfig]. + * Returns an immutable instance of [Browserbase]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): BrowserbaseProxyConfig = - BrowserbaseProxyConfig( + fun build(): Browserbase = + Browserbase( type, domainPattern, geolocation, @@ -6265,7 +6226,7 @@ private constructor( private var validated: Boolean = false - fun validate(): BrowserbaseProxyConfig = apply { + fun validate(): Browserbase = apply { if (validated) { return@apply } @@ -6554,7 +6515,7 @@ private constructor( return true } - return other is BrowserbaseProxyConfig && + return other is Browserbase && type == other.type && domainPattern == other.domainPattern && geolocation == other.geolocation && @@ -6568,10 +6529,10 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "BrowserbaseProxyConfig{type=$type, domainPattern=$domainPattern, geolocation=$geolocation, additionalProperties=$additionalProperties}" + "Browserbase{type=$type, domainPattern=$domainPattern, geolocation=$geolocation, additionalProperties=$additionalProperties}" } - class ExternalProxyConfig + class External @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val server: JsonField, @@ -6691,8 +6652,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [ExternalProxyConfig]. + * Returns a mutable builder for constructing an instance of [External]. * * The following fields are required: * ```java @@ -6702,7 +6662,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [ExternalProxyConfig]. */ + /** A builder for [External]. */ class Builder internal constructor() { private var server: JsonField? = null @@ -6714,14 +6674,13 @@ private constructor( mutableMapOf() @JvmSynthetic - internal fun from(externalProxyConfig: ExternalProxyConfig) = apply { - server = externalProxyConfig.server - type = externalProxyConfig.type - domainPattern = externalProxyConfig.domainPattern - password = externalProxyConfig.password - username = externalProxyConfig.username - additionalProperties = - externalProxyConfig.additionalProperties.toMutableMap() + internal fun from(external: External) = apply { + server = external.server + type = external.type + domainPattern = external.domainPattern + password = external.password + username = external.username + additionalProperties = external.additionalProperties.toMutableMap() } fun server(server: String) = server(JsonField.of(server)) @@ -6812,7 +6771,7 @@ private constructor( } /** - * Returns an immutable instance of [ExternalProxyConfig]. + * Returns an immutable instance of [External]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -6823,8 +6782,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): ExternalProxyConfig = - ExternalProxyConfig( + fun build(): External = + External( checkRequired("server", server), type, domainPattern, @@ -6836,7 +6795,7 @@ private constructor( private var validated: Boolean = false - fun validate(): ExternalProxyConfig = apply { + fun validate(): External = apply { if (validated) { return@apply } @@ -6882,7 +6841,7 @@ private constructor( return true } - return other is ExternalProxyConfig && + return other is External && server == other.server && type == other.type && domainPattern == other.domainPattern && @@ -6905,7 +6864,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "ExternalProxyConfig{server=$server, type=$type, domainPattern=$domainPattern, password=$password, username=$username, additionalProperties=$additionalProperties}" + "External{server=$server, type=$type, domainPattern=$domainPattern, password=$password, username=$username, additionalProperties=$additionalProperties}" } } } @@ -7190,6 +7149,137 @@ private constructor( "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" } + /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ + class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val _0 = of(0L) + + @JvmField val _1 = of(1L) + + @JvmField val _2 = of(2L) + + @JvmStatic fun of(value: Long) = Verbose(JsonField.of(value)) + } + + /** An enum containing [Verbose]'s known values. */ + enum class Known { + _0, + _1, + _2, + } + + /** + * An enum containing [Verbose]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Verbose] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + _0, + _1, + _2, + /** An enum member indicating that [Verbose] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + _0 -> Value._0 + _1 -> Value._1 + _2 -> Value._2 + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + _0 -> Known._0 + _1 -> Known._1 + _2 -> Known._2 + else -> throw StagehandInvalidDataException("Unknown Verbose: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asLong(): Long = + _value().asNumber().getOrNull()?.let { + if (it.toDouble() % 1 == 0.0) it.toLong() else null + } ?: throw StagehandInvalidDataException("Value is not a Long") + + private var validated: Boolean = false + + fun validate(): Verbose = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Verbose && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + /** Client SDK language */ class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index b45bc3f..d83a01a 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -13,19 +13,19 @@ import org.junit.jupiter.api.assertThrows internal class ModelConfigTest { @Test - fun ofString() { - val string = "string" + fun ofName() { + val name = "openai/gpt-5-nano" - val modelConfig = ModelConfig.ofString(string) + val modelConfig = ModelConfig.ofName(name) - assertThat(modelConfig.string()).contains(string) - assertThat(modelConfig.unionMember1()).isEmpty + assertThat(modelConfig.name()).contains(name) + assertThat(modelConfig.modelConfigObject()).isEmpty } @Test - fun ofStringRoundtrip() { + fun ofNameRoundtrip() { val jsonMapper = jsonMapper() - val modelConfig = ModelConfig.ofString("string") + val modelConfig = ModelConfig.ofName("openai/gpt-5-nano") val roundtrippedModelConfig = jsonMapper.readValue( @@ -37,29 +37,29 @@ internal class ModelConfigTest { } @Test - fun ofUnionMember1() { - val unionMember1 = - ModelConfig.UnionMember1.builder() - .modelName("modelName") - .apiKey("apiKey") - .baseUrl("https://example.com") + fun ofModelConfigObject() { + val modelConfigObject = + ModelConfig.ModelConfigObject.builder() + .modelName("gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") .build() - val modelConfig = ModelConfig.ofUnionMember1(unionMember1) + val modelConfig = ModelConfig.ofModelConfigObject(modelConfigObject) - assertThat(modelConfig.string()).isEmpty - assertThat(modelConfig.unionMember1()).contains(unionMember1) + assertThat(modelConfig.name()).isEmpty + assertThat(modelConfig.modelConfigObject()).contains(modelConfigObject) } @Test - fun ofUnionMember1Roundtrip() { + fun ofModelConfigObjectRoundtrip() { val jsonMapper = jsonMapper() val modelConfig = - ModelConfig.ofUnionMember1( - ModelConfig.UnionMember1.builder() - .modelName("modelName") - .apiKey("apiKey") - .baseUrl("https://example.com") + ModelConfig.ofModelConfigObject( + ModelConfig.ModelConfigObject.builder() + .modelName("gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index c31444c..2b5fb57 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -22,7 +22,7 @@ internal class SessionActParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -60,7 +60,7 @@ internal class SessionActParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -110,7 +110,7 @@ internal class SessionActParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -129,7 +129,7 @@ internal class SessionActParamsTest { assertThat(body.options()) .contains( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt index 30e45db..041295f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndResponseTest.kt @@ -11,13 +11,15 @@ internal class SessionEndResponseTest { @Test fun create() { - val sessionEndResponse = SessionEndResponse.builder().build() + val sessionEndResponse = SessionEndResponse.builder().success(true).build() + + assertThat(sessionEndResponse.success()).isEqualTo(true) } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val sessionEndResponse = SessionEndResponse.builder().build() + val sessionEndResponse = SessionEndResponse.builder().success(true).build() val roundtrippedSessionEndResponse = jsonMapper.readValue( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index b40f381..7d7caf8 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -20,7 +20,7 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("string") + .model("openai/gpt-5-nano") .systemPrompt("systemPrompt") .build() ) @@ -69,7 +69,7 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("string") + .model("openai/gpt-5-nano") .systemPrompt("systemPrompt") .build() ) @@ -130,7 +130,7 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("string") + .model("openai/gpt-5-nano") .systemPrompt("systemPrompt") .build() ) @@ -152,7 +152,7 @@ internal class SessionExecuteParamsTest { .isEqualTo( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("string") + .model("openai/gpt-5-nano") .systemPrompt("systemPrompt") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 4a3c252..30bc290 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -22,7 +22,7 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("#main-content") .timeout(30000.0) .build() @@ -58,7 +58,7 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("#main-content") .timeout(30000.0) .build() @@ -106,7 +106,7 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("#main-content") .timeout(30000.0) .build() @@ -126,7 +126,7 @@ internal class SessionExtractParamsTest { assertThat(body.options()) .contains( SessionExtractParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("#main-content") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 95ccd9b..98d7d9a 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -21,7 +21,7 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("nav") .timeout(30000.0) .build() @@ -52,7 +52,7 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("nav") .timeout(30000.0) .build() @@ -95,7 +95,7 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("nav") .timeout(30000.0) .build() @@ -109,7 +109,7 @@ internal class SessionObserveParamsTest { assertThat(body.options()) .contains( SessionObserveParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("nav") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 0dc5811..13ae538 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -153,7 +153,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() } @@ -306,7 +306,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() @@ -480,7 +480,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() @@ -624,7 +624,7 @@ internal class SessionStartParamsTest { assertThat(body.experimental()).contains(true) assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") - assertThat(body.verbose()).contains(1L) + assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) assertThat(body.waitForCaptchaSolves()).contains(true) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 967794c..87af3f1 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -230,7 +230,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -410,7 +410,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -590,7 +590,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -770,7 +770,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -950,7 +950,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1130,7 +1130,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1310,7 +1310,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1490,7 +1490,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1670,7 +1670,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1850,7 +1850,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2030,7 +2030,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2210,7 +2210,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2390,7 +2390,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2570,7 +2570,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2750,7 +2750,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2930,7 +2930,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -3108,7 +3108,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index beb2b92..a50efce 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -192,7 +192,7 @@ internal class ServiceParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") @@ -225,7 +225,7 @@ internal class ServiceParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index fd11f6e..8abcbcb 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -44,7 +44,7 @@ internal class SessionServiceAsyncTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -110,7 +110,7 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("string") + .model("openai/gpt-5-nano") .systemPrompt("systemPrompt") .build() ) @@ -155,7 +155,7 @@ internal class SessionServiceAsyncTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("#main-content") .timeout(30000.0) .build() @@ -232,7 +232,7 @@ internal class SessionServiceAsyncTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("nav") .timeout(30000.0) .build() @@ -406,7 +406,7 @@ internal class SessionServiceAsyncTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index ba02cd0..937b3ea 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -44,7 +44,7 @@ internal class SessionServiceTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -108,7 +108,7 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("string") + .model("openai/gpt-5-nano") .systemPrompt("systemPrompt") .build() ) @@ -152,7 +152,7 @@ internal class SessionServiceTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("#main-content") .timeout(30000.0) .build() @@ -227,7 +227,7 @@ internal class SessionServiceTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("string") + .model("openai/gpt-5-nano") .selector("nav") .timeout(30000.0) .build() @@ -400,7 +400,7 @@ internal class SessionServiceTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 63da21d..0d52560 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -76,7 +76,7 @@ internal class ProGuardCompatibilityTest { @Test fun modelConfigRoundtrip() { val jsonMapper = jsonMapper() - val modelConfig = ModelConfig.ofString("string") + val modelConfig = ModelConfig.ofName("openai/gpt-5-nano") val roundtrippedModelConfig = jsonMapper.readValue( From 9bf158cda8e161689013042b9be58ec12d088891 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 19:06:17 +0000 Subject: [PATCH 035/164] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 38ef77c..65bd734 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-817d1d4e845b1946dac8ee10fd34b3f533aa36f74ac598582ffb1b0399a5a932.yml -openapi_spec_hash: 9d856db62b34909fec94743235b3d7be +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e09ad013e10b6a6bb76dd9b2067696ba92bd7acb862b39bbfe2f296ebdb6eddf.yml +openapi_spec_hash: 2f633591561e4737534842273441a818 config_hash: 88e87ba7021be93d267ecfc8f5e6b891 From a8b29f7aed16d6f0571674cd2eee93712fe5356b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 20:09:02 +0000 Subject: [PATCH 036/164] feat(api): manual updates --- .stats.yml | 6 +- .../api/models/sessions/SessionStartParams.kt | 304 ++++-------------- .../models/sessions/SessionActParamsTest.kt | 8 +- .../models/sessions/SessionEndParamsTest.kt | 6 +- .../sessions/SessionExecuteParamsTest.kt | 8 +- .../sessions/SessionExtractParamsTest.kt | 8 +- .../sessions/SessionNavigateParamsTest.kt | 8 +- .../sessions/SessionObserveParamsTest.kt | 8 +- .../models/sessions/SessionStartParamsTest.kt | 16 +- .../api/services/ErrorHandlingTest.kt | 68 ++-- .../api/services/ServiceParamsTest.kt | 6 +- .../services/async/SessionServiceAsyncTest.kt | 16 +- .../services/blocking/SessionServiceTest.kt | 16 +- 13 files changed, 156 insertions(+), 322 deletions(-) diff --git a/.stats.yml b/.stats.yml index 65bd734..604325f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e09ad013e10b6a6bb76dd9b2067696ba92bd7acb862b39bbfe2f296ebdb6eddf.yml -openapi_spec_hash: 2f633591561e4737534842273441a818 -config_hash: 88e87ba7021be93d267ecfc8f5e6b891 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e96507dd78e76fccc77ba7fb09704da127ead6f4d73ea854e9b2150e90787ff4.yml +openapi_spec_hash: 0c2548b8fdd6de6789b19123e69609c1 +config_hash: c3abb41dbe698d59b3bf12f393013d54 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 57f072f..16eecb4 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -142,7 +142,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun verbose(): Optional = body.verbose() + fun verbose(): Optional = body.verbose() /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the @@ -229,7 +229,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - fun _verbose(): JsonField = body._verbose() + fun _verbose(): JsonField = body._verbose() /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -459,15 +459,15 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Verbose) = apply { body.verbose(verbose) } + fun verbose(verbose: Long) = apply { body.verbose(verbose) } /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. This + * You should usually call [Builder.verbose] with a well-typed [Long] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = apply { body.waitForCaptchaSolves(waitForCaptchaSolves) @@ -653,7 +653,7 @@ private constructor( private val experimental: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, - private val verbose: JsonField, + private val verbose: JsonField, private val waitForCaptchaSolves: JsonField, private val additionalProperties: MutableMap, ) { @@ -689,7 +689,7 @@ private constructor( @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), + @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), @JsonProperty("waitForCaptchaSolves") @ExcludeMissing waitForCaptchaSolves: JsonField = JsonMissing.of(), @@ -790,7 +790,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verbose(): Optional = verbose.getOptional("verbose") + fun verbose(): Optional = verbose.getOptional("verbose") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if @@ -893,7 +893,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose + @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -944,7 +944,7 @@ private constructor( private var experimental: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() - private var verbose: JsonField = JsonMissing.of() + private var verbose: JsonField = JsonMissing.of() private var waitForCaptchaSolves: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -1098,16 +1098,16 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Verbose) = verbose(JsonField.of(verbose)) + fun verbose(verbose: Long) = verbose(JsonField.of(verbose)) /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. + * You should usually call [Builder.verbose] with a well-typed [Long] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + fun verbose(verbose: JsonField) = apply { this.verbose = verbose } fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = waitForCaptchaSolves(JsonField.of(waitForCaptchaSolves)) @@ -1189,7 +1189,7 @@ private constructor( experimental() selfHeal() systemPrompt() - verbose().ifPresent { it.validate() } + verbose() waitForCaptchaSolves() validated = true } @@ -1220,7 +1220,7 @@ private constructor( (if (experimental.asKnown().isPresent) 1 else 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + - (verbose.asKnown().getOrNull()?.validity() ?: 0) + + (if (verbose.asKnown().isPresent) 1 else 0) + (if (waitForCaptchaSolves.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -3408,13 +3408,9 @@ private constructor( /** Alias for calling [proxies] with `Proxies.ofBool(bool)`. */ fun proxies(bool: Boolean) = proxies(Proxies.ofBool(bool)) - /** - * Alias for calling [proxies] with - * `Proxies.ofUnnamedSchemaWithArrayParent0s(unnamedSchemaWithArrayParent0s)`. - */ - fun proxiesOfUnnamedSchemaWithArrayParent0s( - unnamedSchemaWithArrayParent0s: List - ) = proxies(Proxies.ofUnnamedSchemaWithArrayParent0s(unnamedSchemaWithArrayParent0s)) + /** Alias for calling [proxies] with `Proxies.ofProxyConfigList(proxyConfigList)`. */ + fun proxiesOfProxyConfigList(proxyConfigList: List) = + proxies(Proxies.ofProxyConfigList(proxyConfigList)) fun region(region: Region) = region(JsonField.of(region)) @@ -5668,31 +5664,30 @@ private constructor( class Proxies private constructor( private val bool: Boolean? = null, - private val unnamedSchemaWithArrayParent0s: List? = null, + private val proxyConfigList: List? = null, private val _json: JsonValue? = null, ) { fun bool(): Optional = Optional.ofNullable(bool) - fun unnamedSchemaWithArrayParent0s(): Optional> = - Optional.ofNullable(unnamedSchemaWithArrayParent0s) + fun proxyConfigList(): Optional> = + Optional.ofNullable(proxyConfigList) fun isBool(): Boolean = bool != null - fun isUnnamedSchemaWithArrayParent0s(): Boolean = unnamedSchemaWithArrayParent0s != null + fun isProxyConfigList(): Boolean = proxyConfigList != null fun asBool(): Boolean = bool.getOrThrow("bool") - fun asUnnamedSchemaWithArrayParent0s(): List = - unnamedSchemaWithArrayParent0s.getOrThrow("unnamedSchemaWithArrayParent0s") + fun asProxyConfigList(): List = + proxyConfigList.getOrThrow("proxyConfigList") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { bool != null -> visitor.visitBool(bool) - unnamedSchemaWithArrayParent0s != null -> - visitor.visitUnnamedSchemaWithArrayParent0s(unnamedSchemaWithArrayParent0s) + proxyConfigList != null -> visitor.visitProxyConfigList(proxyConfigList) else -> visitor.unknown(_json) } @@ -5707,10 +5702,8 @@ private constructor( object : Visitor { override fun visitBool(bool: Boolean) {} - override fun visitUnnamedSchemaWithArrayParent0s( - unnamedSchemaWithArrayParent0s: List - ) { - unnamedSchemaWithArrayParent0s.forEach { it.validate() } + override fun visitProxyConfigList(proxyConfigList: List) { + proxyConfigList.forEach { it.validate() } } } ) @@ -5737,9 +5730,8 @@ private constructor( object : Visitor { override fun visitBool(bool: Boolean) = 1 - override fun visitUnnamedSchemaWithArrayParent0s( - unnamedSchemaWithArrayParent0s: List - ) = unnamedSchemaWithArrayParent0s.sumOf { it.validity().toInt() } + override fun visitProxyConfigList(proxyConfigList: List) = + proxyConfigList.sumOf { it.validity().toInt() } override fun unknown(json: JsonValue?) = 0 } @@ -5752,16 +5744,15 @@ private constructor( return other is Proxies && bool == other.bool && - unnamedSchemaWithArrayParent0s == other.unnamedSchemaWithArrayParent0s + proxyConfigList == other.proxyConfigList } - override fun hashCode(): Int = Objects.hash(bool, unnamedSchemaWithArrayParent0s) + override fun hashCode(): Int = Objects.hash(bool, proxyConfigList) override fun toString(): String = when { bool != null -> "Proxies{bool=$bool}" - unnamedSchemaWithArrayParent0s != null -> - "Proxies{unnamedSchemaWithArrayParent0s=$unnamedSchemaWithArrayParent0s}" + proxyConfigList != null -> "Proxies{proxyConfigList=$proxyConfigList}" _json != null -> "Proxies{_unknown=$_json}" else -> throw IllegalStateException("Invalid Proxies") } @@ -5771,13 +5762,8 @@ private constructor( @JvmStatic fun ofBool(bool: Boolean) = Proxies(bool = bool) @JvmStatic - fun ofUnnamedSchemaWithArrayParent0s( - unnamedSchemaWithArrayParent0s: List - ) = - Proxies( - unnamedSchemaWithArrayParent0s = - unnamedSchemaWithArrayParent0s.toImmutable() - ) + fun ofProxyConfigList(proxyConfigList: List) = + Proxies(proxyConfigList = proxyConfigList.toImmutable()) } /** @@ -5788,9 +5774,7 @@ private constructor( fun visitBool(bool: Boolean): T - fun visitUnnamedSchemaWithArrayParent0s( - unnamedSchemaWithArrayParent0s: List - ): T + fun visitProxyConfigList(proxyConfigList: List): T /** * Maps an unknown variant of [Proxies] to a value of type [T]. @@ -5817,13 +5801,9 @@ private constructor( tryDeserialize(node, jacksonTypeRef())?.let { Proxies(bool = it, _json = json) }, - tryDeserialize( - node, - jacksonTypeRef>(), - ) - ?.let { - Proxies(unnamedSchemaWithArrayParent0s = it, _json = json) - }, + tryDeserialize(node, jacksonTypeRef>())?.let { + Proxies(proxyConfigList = it, _json = json) + }, ) .filterNotNull() .allMaxBy { it.validity() } @@ -5850,17 +5830,17 @@ private constructor( ) { when { value.bool != null -> generator.writeObject(value.bool) - value.unnamedSchemaWithArrayParent0s != null -> - generator.writeObject(value.unnamedSchemaWithArrayParent0s) + value.proxyConfigList != null -> + generator.writeObject(value.proxyConfigList) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid Proxies") } } } - @JsonDeserialize(using = UnnamedSchemaWithArrayParent0.Deserializer::class) - @JsonSerialize(using = UnnamedSchemaWithArrayParent0.Serializer::class) - class UnnamedSchemaWithArrayParent0 + @JsonDeserialize(using = ProxyConfig.Deserializer::class) + @JsonSerialize(using = ProxyConfig.Serializer::class) + class ProxyConfig private constructor( private val browserbase: Browserbase? = null, private val external: External? = null, @@ -5890,7 +5870,7 @@ private constructor( private var validated: Boolean = false - fun validate(): UnnamedSchemaWithArrayParent0 = apply { + fun validate(): ProxyConfig = apply { if (validated) { return@apply } @@ -5941,7 +5921,7 @@ private constructor( return true } - return other is UnnamedSchemaWithArrayParent0 && + return other is ProxyConfig && browserbase == other.browserbase && external == other.external } @@ -5950,27 +5930,24 @@ private constructor( override fun toString(): String = when { - browserbase != null -> - "UnnamedSchemaWithArrayParent0{browserbase=$browserbase}" - external != null -> "UnnamedSchemaWithArrayParent0{external=$external}" - _json != null -> "UnnamedSchemaWithArrayParent0{_unknown=$_json}" - else -> throw IllegalStateException("Invalid UnnamedSchemaWithArrayParent0") + browserbase != null -> "ProxyConfig{browserbase=$browserbase}" + external != null -> "ProxyConfig{external=$external}" + _json != null -> "ProxyConfig{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ProxyConfig") } companion object { @JvmStatic fun ofBrowserbase(browserbase: Browserbase) = - UnnamedSchemaWithArrayParent0(browserbase = browserbase) + ProxyConfig(browserbase = browserbase) - @JvmStatic - fun ofExternal(external: External) = - UnnamedSchemaWithArrayParent0(external = external) + @JvmStatic fun ofExternal(external: External) = ProxyConfig(external = external) } /** - * An interface that defines how to map each variant of - * [UnnamedSchemaWithArrayParent0] to a value of type [T]. + * An interface that defines how to map each variant of [ProxyConfig] to a value of + * type [T]. */ interface Visitor { @@ -5979,58 +5956,47 @@ private constructor( fun visitExternal(external: External): T /** - * Maps an unknown variant of [UnnamedSchemaWithArrayParent0] to a value of type - * [T]. + * Maps an unknown variant of [ProxyConfig] to a value of type [T]. * - * An instance of [UnnamedSchemaWithArrayParent0] can contain an unknown variant - * if it was deserialized from data that doesn't match any known variant. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new variants that the SDK is unaware of. + * An instance of [ProxyConfig] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if + * the SDK is on an older version than the API, then the API may respond with + * new variants that the SDK is unaware of. * * @throws StagehandInvalidDataException in the default implementation. */ fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException( - "Unknown UnnamedSchemaWithArrayParent0: $json" - ) + throw StagehandInvalidDataException("Unknown ProxyConfig: $json") } } - internal class Deserializer : - BaseDeserializer( - UnnamedSchemaWithArrayParent0::class - ) { + internal class Deserializer : BaseDeserializer(ProxyConfig::class) { - override fun ObjectCodec.deserialize( - node: JsonNode - ): UnnamedSchemaWithArrayParent0 { + override fun ObjectCodec.deserialize(node: JsonNode): ProxyConfig { val json = JsonValue.fromJsonNode(node) val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() when (type) { "browserbase" -> { return tryDeserialize(node, jacksonTypeRef())?.let { - UnnamedSchemaWithArrayParent0(browserbase = it, _json = json) - } ?: UnnamedSchemaWithArrayParent0(_json = json) + ProxyConfig(browserbase = it, _json = json) + } ?: ProxyConfig(_json = json) } "external" -> { return tryDeserialize(node, jacksonTypeRef())?.let { - UnnamedSchemaWithArrayParent0(external = it, _json = json) - } ?: UnnamedSchemaWithArrayParent0(_json = json) + ProxyConfig(external = it, _json = json) + } ?: ProxyConfig(_json = json) } } - return UnnamedSchemaWithArrayParent0(_json = json) + return ProxyConfig(_json = json) } } - internal class Serializer : - BaseSerializer( - UnnamedSchemaWithArrayParent0::class - ) { + internal class Serializer : BaseSerializer(ProxyConfig::class) { override fun serialize( - value: UnnamedSchemaWithArrayParent0, + value: ProxyConfig, generator: JsonGenerator, provider: SerializerProvider, ) { @@ -6038,8 +6004,7 @@ private constructor( value.browserbase != null -> generator.writeObject(value.browserbase) value.external != null -> generator.writeObject(value.external) value._json != null -> generator.writeObject(value._json) - else -> - throw IllegalStateException("Invalid UnnamedSchemaWithArrayParent0") + else -> throw IllegalStateException("Invalid ProxyConfig") } } } @@ -7149,137 +7114,6 @@ private constructor( "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" } - /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val _0 = of(0L) - - @JvmField val _1 = of(1L) - - @JvmField val _2 = of(2L) - - @JvmStatic fun of(value: Long) = Verbose(JsonField.of(value)) - } - - /** An enum containing [Verbose]'s known values. */ - enum class Known { - _0, - _1, - _2, - } - - /** - * An enum containing [Verbose]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Verbose] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - _0, - _1, - _2, - /** An enum member indicating that [Verbose] was instantiated with an unknown value. */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - _0 -> Value._0 - _1 -> Value._1 - _2 -> Value._2 - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - _0 -> Known._0 - _1 -> Known._1 - _2 -> Known._2 - else -> throw StagehandInvalidDataException("Unknown Verbose: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asLong(): Long = - _value().asNumber().getOrNull()?.let { - if (it.toDouble() % 1 == 0.0) it.toLong() else null - } ?: throw StagehandInvalidDataException("Value is not a Long") - - private var validated: Boolean = false - - fun validate(): Verbose = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Verbose && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Client SDK language */ class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 2b5fb57..9c19cb7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -16,7 +16,7 @@ internal class SessionActParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") @@ -54,7 +54,7 @@ internal class SessionActParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") @@ -78,7 +78,7 @@ internal class SessionActParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) @@ -104,7 +104,7 @@ internal class SessionActParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 14faac3..bc50272 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -15,7 +15,7 @@ internal class SessionEndParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() } @@ -36,7 +36,7 @@ internal class SessionEndParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() @@ -47,7 +47,7 @@ internal class SessionEndParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 7d7caf8..4de6985 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -15,7 +15,7 @@ internal class SessionExecuteParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() @@ -64,7 +64,7 @@ internal class SessionExecuteParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() @@ -92,7 +92,7 @@ internal class SessionExecuteParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) @@ -125,7 +125,7 @@ internal class SessionExecuteParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 30bc290..b8d0a00 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -16,7 +16,7 @@ internal class SessionExtractParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") @@ -52,7 +52,7 @@ internal class SessionExtractParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") @@ -77,7 +77,7 @@ internal class SessionExtractParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) @@ -100,7 +100,7 @@ internal class SessionExtractParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt index aa845c3..3bba7d4 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -15,7 +15,7 @@ internal class SessionNavigateParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -49,7 +49,7 @@ internal class SessionNavigateParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -69,7 +69,7 @@ internal class SessionNavigateParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) @@ -95,7 +95,7 @@ internal class SessionNavigateParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 98d7d9a..db03460 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -15,7 +15,7 @@ internal class SessionObserveParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") @@ -46,7 +46,7 @@ internal class SessionObserveParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") @@ -66,7 +66,7 @@ internal class SessionObserveParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) @@ -89,7 +89,7 @@ internal class SessionObserveParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 13ae538..56f4736 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -15,7 +15,7 @@ internal class SessionStartParamsTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -153,7 +153,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() } @@ -164,7 +164,7 @@ internal class SessionStartParamsTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -306,7 +306,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() @@ -317,7 +317,7 @@ internal class SessionStartParamsTest { Headers.builder() .put("x-language", "typescript") .put("x-sdk-version", "3.0.6") - .put("x-sent-at", "2025-01-15T10:30:00.000Z") + .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() ) @@ -338,7 +338,7 @@ internal class SessionStartParamsTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -480,7 +480,7 @@ internal class SessionStartParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() @@ -624,7 +624,7 @@ internal class SessionStartParamsTest { assertThat(body.experimental()).contains(true) assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") - assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) + assertThat(body.verbose()).contains(1L) assertThat(body.waitForCaptchaSolves()).contains(true) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 87af3f1..e453d81 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -77,7 +77,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -230,7 +230,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -257,7 +257,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -410,7 +410,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -437,7 +437,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -590,7 +590,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -617,7 +617,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -770,7 +770,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -797,7 +797,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -950,7 +950,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -977,7 +977,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -1130,7 +1130,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1157,7 +1157,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -1310,7 +1310,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1337,7 +1337,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -1490,7 +1490,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1517,7 +1517,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -1670,7 +1670,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1697,7 +1697,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -1850,7 +1850,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -1877,7 +1877,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -2030,7 +2030,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2057,7 +2057,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -2210,7 +2210,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2237,7 +2237,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -2390,7 +2390,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2417,7 +2417,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -2570,7 +2570,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2597,7 +2597,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -2750,7 +2750,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2777,7 +2777,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -2930,7 +2930,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) @@ -2955,7 +2955,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -3108,7 +3108,7 @@ internal class ErrorHandlingTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index a50efce..0cdc99d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -50,7 +50,7 @@ internal class ServiceParamsTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -192,7 +192,7 @@ internal class ServiceParamsTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") @@ -219,7 +219,7 @@ internal class ServiceParamsTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 8abcbcb..270a06b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -38,7 +38,7 @@ internal class SessionServiceAsyncTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") @@ -78,7 +78,7 @@ internal class SessionServiceAsyncTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() ) @@ -105,7 +105,7 @@ internal class SessionServiceAsyncTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() @@ -149,7 +149,7 @@ internal class SessionServiceAsyncTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") @@ -190,7 +190,7 @@ internal class SessionServiceAsyncTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -226,7 +226,7 @@ internal class SessionServiceAsyncTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") @@ -261,7 +261,7 @@ internal class SessionServiceAsyncTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -406,7 +406,7 @@ internal class SessionServiceAsyncTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 937b3ea..af06455 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -38,7 +38,7 @@ internal class SessionServiceTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") @@ -77,7 +77,7 @@ internal class SessionServiceTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) .build() ) @@ -103,7 +103,7 @@ internal class SessionServiceTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() @@ -146,7 +146,7 @@ internal class SessionServiceTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") @@ -186,7 +186,7 @@ internal class SessionServiceTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -221,7 +221,7 @@ internal class SessionServiceTest { .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") @@ -255,7 +255,7 @@ internal class SessionServiceTest { SessionStartParams.builder() .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) .xSdkVersion("3.0.6") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00.000Z")) + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") .actTimeoutMs(30000.0) @@ -400,7 +400,7 @@ internal class SessionServiceTest { .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(SessionStartParams.Verbose._1) + .verbose(1L) .waitForCaptchaSolves(true) .build() ) From 11bd256f9d91784a005ba8f9c17e3a15990ae9ad Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 01:38:54 +0000 Subject: [PATCH 037/164] feat(api): manual updates --- .stats.yml | 6 +- README.md | 2 + .../client/okhttp/StagehandOkHttpClient.kt | 13 + .../okhttp/StagehandOkHttpClientAsync.kt | 13 + .../com/browserbase/api/core/ClientOptions.kt | 50 + .../api/core/handlers/SseHandler.kt | 137 ++ .../api/core/handlers/StreamHandler.kt | 102 ++ .../browserbase/api/core/http/SseMessage.kt | 74 ++ .../browserbase/api/errors/SseException.kt | 91 ++ .../api/models/sessions/SessionActParams.kt | 326 +---- .../models/sessions/SessionNavigateParams.kt | 81 +- .../models/sessions/SessionStartResponse.kt | 51 +- .../api/models/sessions/StreamEvent.kt | 1175 +++++++++++++++++ .../api/services/async/SessionServiceAsync.kt | 291 ++++ .../services/async/SessionServiceAsyncImpl.kt | 228 ++++ .../api/services/blocking/SessionService.kt | 294 +++++ .../services/blocking/SessionServiceImpl.kt | 202 +++ .../api/core/handlers/SseHandlerTest.kt | 134 ++ .../api/core/handlers/StreamHandlerTest.kt | 94 ++ .../sessions/SessionNavigateParamsTest.kt | 4 + .../sessions/SessionStartResponseTest.kt | 3 + .../api/models/sessions/StreamEventTest.kt | 66 + .../services/async/SessionServiceAsyncTest.kt | 166 +++ .../services/blocking/SessionServiceTest.kt | 166 +++ 24 files changed, 3441 insertions(+), 328 deletions(-) create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StreamHandler.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/SseMessage.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/StreamHandlerTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/StreamEventTest.kt diff --git a/.stats.yml b/.stats.yml index 604325f..5dba58c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-e96507dd78e76fccc77ba7fb09704da127ead6f4d73ea854e9b2150e90787ff4.yml -openapi_spec_hash: 0c2548b8fdd6de6789b19123e69609c1 -config_hash: c3abb41dbe698d59b3bf12f393013d54 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-f7d6b6489159f611a2bfdc267ce0a6fc0455bed1ffa0c310044baaa5d8381b9b.yml +openapi_spec_hash: cd88d8068abfde8382da0bed674e440c +config_hash: 5c69fb596588b8ace08203858518c149 diff --git a/README.md b/README.md index 3c37038..be1932d 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,8 @@ The SDK throws custom unchecked exception types: | 5xx | [`InternalServerException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt) | | others | [`UnexpectedStatusCodeException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt) | + [`SseException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt) is thrown for errors encountered during [SSE streaming](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) after a successful initial HTTP response. + - [`StagehandIoException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandIoException.kt): I/O networking errors. - [`StagehandRetryableException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandRetryableException.kt): Generic error indicating a failure that could be retried by the client. diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index 8955635..40010ee 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -7,6 +7,7 @@ import com.browserbase.api.client.StagehandClientImpl import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.Sleeper import com.browserbase.api.core.Timeout +import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpClient import com.browserbase.api.core.http.QueryParams @@ -16,6 +17,7 @@ import java.net.Proxy import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.Executor import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -121,6 +123,17 @@ class StagehandOkHttpClient private constructor() { */ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } + /** + * The executor to use for running [AsyncStreamResponse.Handler] callbacks. + * + * Defaults to a dedicated cached thread pool. + * + * This class takes ownership of the executor and shuts it down, if possible, when closed. + */ + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + clientOptions.streamHandlerExecutor(streamHandlerExecutor) + } + /** * The interface to use for delaying execution, like during retries. * diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 2cb208d..33ce68f 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -7,6 +7,7 @@ import com.browserbase.api.client.StagehandClientAsyncImpl import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.Sleeper import com.browserbase.api.core.Timeout +import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpClient import com.browserbase.api.core.http.QueryParams @@ -16,6 +17,7 @@ import java.net.Proxy import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.Executor import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -121,6 +123,17 @@ class StagehandOkHttpClientAsync private constructor() { */ fun jsonMapper(jsonMapper: JsonMapper) = apply { clientOptions.jsonMapper(jsonMapper) } + /** + * The executor to use for running [AsyncStreamResponse.Handler] callbacks. + * + * Defaults to a dedicated cached thread pool. + * + * This class takes ownership of the executor and shuts it down, if possible, when closed. + */ + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + clientOptions.streamHandlerExecutor(streamHandlerExecutor) + } + /** * The interface to use for delaying execution, like during retries. * diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 8692cb0..2da3f9a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -2,6 +2,7 @@ package com.browserbase.api.core +import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpClient import com.browserbase.api.core.http.PhantomReachableClosingHttpClient @@ -11,6 +12,11 @@ import com.fasterxml.jackson.databind.json.JsonMapper import java.time.Clock import java.time.Duration import java.util.Optional +import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.ThreadFactory +import java.util.concurrent.atomic.AtomicLong import kotlin.jvm.optionals.getOrNull /** A class representing the SDK client configuration. */ @@ -40,6 +46,14 @@ private constructor( * rarely needs to be overridden. */ @get:JvmName("jsonMapper") val jsonMapper: JsonMapper, + /** + * The executor to use for running [AsyncStreamResponse.Handler] callbacks. + * + * Defaults to a dedicated cached thread pool. + * + * This class takes ownership of the executor and shuts it down, if possible, when closed. + */ + @get:JvmName("streamHandlerExecutor") val streamHandlerExecutor: Executor, /** * The interface to use for delaying execution, like during retries. * @@ -147,6 +161,7 @@ private constructor( private var httpClient: HttpClient? = null private var checkJacksonVersionCompatibility: Boolean = true private var jsonMapper: JsonMapper = jsonMapper() + private var streamHandlerExecutor: Executor? = null private var sleeper: Sleeper? = null private var clock: Clock = Clock.systemUTC() private var baseUrl: String? = null @@ -164,6 +179,7 @@ private constructor( httpClient = clientOptions.originalHttpClient checkJacksonVersionCompatibility = clientOptions.checkJacksonVersionCompatibility jsonMapper = clientOptions.jsonMapper + streamHandlerExecutor = clientOptions.streamHandlerExecutor sleeper = clientOptions.sleeper clock = clientOptions.clock baseUrl = clientOptions.baseUrl @@ -207,6 +223,20 @@ private constructor( */ fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } + /** + * The executor to use for running [AsyncStreamResponse.Handler] callbacks. + * + * Defaults to a dedicated cached thread pool. + * + * This class takes ownership of the executor and shuts it down, if possible, when closed. + */ + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = + if (streamHandlerExecutor is ExecutorService) + PhantomReachableExecutorService(streamHandlerExecutor) + else streamHandlerExecutor + } + /** * The interface to use for delaying execution, like during retries. * @@ -422,6 +452,24 @@ private constructor( */ fun build(): ClientOptions { val httpClient = checkRequired("httpClient", httpClient) + val streamHandlerExecutor = + streamHandlerExecutor + ?: PhantomReachableExecutorService( + Executors.newCachedThreadPool( + object : ThreadFactory { + + private val threadFactory: ThreadFactory = + Executors.defaultThreadFactory() + private val count = AtomicLong(0) + + override fun newThread(runnable: Runnable): Thread = + threadFactory.newThread(runnable).also { + it.name = + "stagehand-stream-handler-thread-${count.getAndIncrement()}" + } + } + ) + ) val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) val browserbaseApiKey = checkRequired("browserbaseApiKey", browserbaseApiKey) val browserbaseProjectId = checkRequired("browserbaseProjectId", browserbaseProjectId) @@ -464,6 +512,7 @@ private constructor( .build(), checkJacksonVersionCompatibility, jsonMapper, + streamHandlerExecutor, sleeper, clock, baseUrl, @@ -491,6 +540,7 @@ private constructor( */ fun close() { httpClient.close() + (streamHandlerExecutor as? ExecutorService)?.shutdown() sleeper.close() } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt new file mode 100644 index 0000000..039faae --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -0,0 +1,137 @@ +// File generated from our OpenAPI spec by Stainless. + +@file:JvmName("SseHandler") + +package com.browserbase.api.core.handlers + +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler +import com.browserbase.api.core.http.SseMessage +import com.browserbase.api.core.http.StreamResponse +import com.browserbase.api.core.http.map +import com.browserbase.api.errors.SseException +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef + +@JvmSynthetic +internal fun sseHandler(jsonMapper: JsonMapper): Handler> = + streamHandler { response, lines -> + val state = SseState(jsonMapper) + var done = false + for (line in lines) { + // Stop emitting messages, but iterate through the full stream. + if (done) { + continue + } + + val message = state.decode(line) ?: continue + + when { + message.data.startsWith("finished") -> { + // In this case we don't break because we still want to iterate through the full + // stream. + done = true + continue + } + message.data.startsWith("error") -> { + throw SseException.builder() + .statusCode(response.statusCode()) + .headers(response.headers()) + .body( + try { + jsonMapper.readValue(message.data, jacksonTypeRef()) + } catch (e: Exception) { + JsonMissing.of() + } + ) + .build() + } + } + + if (message.event == null) { + yield(message) + } + } + } + +private class SseState( + val jsonMapper: JsonMapper, + var event: String? = null, + val data: MutableList = mutableListOf(), + var lastId: String? = null, + var retry: Int? = null, +) { + // https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation + fun decode(line: String): SseMessage? { + if (line.isEmpty()) { + return flush() + } + + if (line.startsWith(':')) { + return null + } + + val fieldName: String + var value: String + + val colonIndex = line.indexOf(':') + if (colonIndex == -1) { + fieldName = line + value = "" + } else { + fieldName = line.substring(0, colonIndex) + value = line.substring(colonIndex + 1) + } + + if (value.startsWith(' ')) { + value = value.substring(1) + } + + when (fieldName) { + "event" -> event = value + "data" -> data.add(value) + "id" -> { + if (!value.contains('\u0000')) { + lastId = value + } + } + "retry" -> value.toIntOrNull()?.let { retry = it } + } + + return null + } + + private fun flush(): SseMessage? { + if (isEmpty()) { + return null + } + + val message = + SseMessage.builder() + .jsonMapper(jsonMapper) + .event(event) + .data(data.joinToString("\n")) + .id(lastId) + .retry(retry) + .build() + + // NOTE: Per the SSE spec, do not reset lastId. + event = null + data.clear() + retry = null + + return message + } + + private fun isEmpty(): Boolean = + event.isNullOrEmpty() && data.isEmpty() && lastId.isNullOrEmpty() && retry == null +} + +@JvmSynthetic +internal inline fun Handler>.mapJson(): + Handler> = + object : Handler> { + override fun handle(response: HttpResponse): StreamResponse = + this@mapJson.handle(response).map { it.json() } + } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StreamHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StreamHandler.kt new file mode 100644 index 0000000..4cd4f25 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/StreamHandler.kt @@ -0,0 +1,102 @@ +@file:JvmName("StreamHandler") + +package com.browserbase.api.core.handlers + +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.HttpResponse.Handler +import com.browserbase.api.core.http.PhantomReachableClosingStreamResponse +import com.browserbase.api.core.http.StreamResponse +import com.browserbase.api.errors.StagehandIoException +import java.io.IOException +import java.util.stream.Stream +import kotlin.streams.asStream + +@JvmSynthetic +internal fun streamHandler( + block: suspend SequenceScope.(response: HttpResponse, lines: Sequence) -> Unit +): Handler> = + object : Handler> { + + override fun handle(response: HttpResponse): StreamResponse { + val reader = response.body().bufferedReader() + val sequence = + // Wrap in a `CloseableSequence` to avoid performing a read on the `reader` + // after it has been closed, which would throw an `IOException`. + CloseableSequence( + sequence { + reader.useLines { lines -> + block( + response, + // We wrap the `lines` instead of the top-level sequence because + // we only want to catch `IOException` from the reader; not from + // the user's own code. + IOExceptionWrappingSequence(lines), + ) + } + } + .constrainOnce() + ) + + return PhantomReachableClosingStreamResponse( + object : StreamResponse { + + override fun stream(): Stream = sequence.asStream() + + override fun close() { + sequence.close() + reader.close() + response.close() + } + } + ) + } + } + +/** A sequence that catches, wraps, and rethrows [IOException] as [StagehandIoException]. */ +private class IOExceptionWrappingSequence(private val sequence: Sequence) : Sequence { + + override fun iterator(): Iterator { + val iterator = sequence.iterator() + return object : Iterator { + + override fun next(): T = + try { + iterator.next() + } catch (e: IOException) { + throw StagehandIoException("Stream failed", e) + } + + override fun hasNext(): Boolean = + try { + iterator.hasNext() + } catch (e: IOException) { + throw StagehandIoException("Stream failed", e) + } + } + } +} + +/** + * A sequence that can be closed. + * + * Once [close] is called, it will not yield more elements. It will also no longer consult the + * underlying [Iterator.hasNext] method. + */ +private class CloseableSequence(private val sequence: Sequence) : Sequence { + + private var isClosed: Boolean = false + + override fun iterator(): Iterator { + val iterator = sequence.iterator() + return object : Iterator { + + override fun next(): T = iterator.next() + + override fun hasNext(): Boolean = !isClosed && iterator.hasNext() + } + } + + fun close() { + isClosed = true + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/SseMessage.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/SseMessage.kt new file mode 100644 index 0000000..21cc44e --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/SseMessage.kt @@ -0,0 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.core.http + +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.util.Objects + +internal class SseMessage +private constructor( + val jsonMapper: JsonMapper, + val event: String?, + val data: String, + val id: String?, + val retry: Int?, +) { + + companion object { + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + + private var jsonMapper: JsonMapper? = null + private var event: String? = null + private var data: String = "" + private var id: String? = null + private var retry: Int? = null + + fun jsonMapper(jsonMapper: JsonMapper) = apply { this.jsonMapper = jsonMapper } + + fun event(event: String?) = apply { this.event = event } + + fun data(data: String) = apply { this.data = data } + + fun id(id: String?) = apply { this.id = id } + + fun retry(retry: Int?) = apply { this.retry = retry } + + fun build(): SseMessage = SseMessage(jsonMapper!!, event, data, id, retry) + } + + inline fun json(): T = + try { + jsonMapper.readerFor(jacksonTypeRef()).readValue(jsonNode) + } catch (e: Exception) { + throw StagehandInvalidDataException("Error reading response", e) + } + + private val jsonNode by lazy { + try { + jsonMapper.readTree(data) + } catch (e: Exception) { + throw StagehandInvalidDataException("Error reading response", e) + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SseMessage && + event == other.event && + data == other.data && + id == other.id && + retry == other.retry + } + + override fun hashCode(): Int = Objects.hash(event, data, id, retry) + + override fun toString(): String = "SseMessage{event=$event, data=$data, id=$id, retry=$retry}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt new file mode 100644 index 0000000..0dfdd2f --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt @@ -0,0 +1,91 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.errors + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.http.Headers +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class SseException +private constructor( + private val statusCode: Int, + private val headers: Headers, + private val body: JsonValue, + cause: Throwable?, +) : StagehandServiceException("$statusCode: $body", cause) { + + override fun statusCode(): Int = statusCode + + override fun headers(): Headers = headers + + override fun body(): JsonValue = body + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SseException]. + * + * The following fields are required: + * ```java + * .statusCode() + * .headers() + * .body() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SseException]. */ + class Builder internal constructor() { + + private var statusCode: Int? = null + private var headers: Headers? = null + private var body: JsonValue? = null + private var cause: Throwable? = null + + @JvmSynthetic + internal fun from(sseException: SseException) = apply { + statusCode = sseException.statusCode + headers = sseException.headers + body = sseException.body + cause = sseException.cause + } + + fun statusCode(statusCode: Int) = apply { this.statusCode = statusCode } + + fun headers(headers: Headers) = apply { this.headers = headers } + + fun body(body: JsonValue) = apply { this.body = body } + + fun cause(cause: Throwable?) = apply { this.cause = cause } + + /** Alias for calling [Builder.cause] with `cause.orElse(null)`. */ + fun cause(cause: Optional) = cause(cause.getOrNull()) + + /** + * Returns an immutable instance of [SseException]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .statusCode() + * .headers() + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SseException = + SseException( + checkRequired("statusCode", statusCode), + checkRequired("headers", headers), + checkRequired("body", body), + cause, + ) + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 019f026..a37780c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -11,7 +11,6 @@ import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.allMaxBy -import com.browserbase.api.core.checkKnown import com.browserbase.api.core.checkRequired import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers @@ -213,7 +212,7 @@ private constructor( fun input(string: String) = apply { body.input(string) } /** Alias for calling [input] with `Input.ofAction(action)`. */ - fun input(action: Input.ActionInput) = apply { body.input(action) } + fun input(action: Action) = apply { body.input(action) } /** Target frame ID for the action */ fun frameId(frameId: String) = apply { body.frameId(frameId) } @@ -515,7 +514,7 @@ private constructor( fun input(string: String) = input(Input.ofString(string)) /** Alias for calling [input] with `Input.ofAction(action)`. */ - fun input(action: Input.ActionInput) = input(Input.ofAction(action)) + fun input(action: Action) = input(Input.ofAction(action)) /** Target frame ID for the action */ fun frameId(frameId: String) = frameId(JsonField.of(frameId)) @@ -641,14 +640,14 @@ private constructor( class Input private constructor( private val string: String? = null, - private val action: ActionInput? = null, + private val action: Action? = null, private val _json: JsonValue? = null, ) { fun string(): Optional = Optional.ofNullable(string) /** Action object returned by observe and used by act */ - fun action(): Optional = Optional.ofNullable(action) + fun action(): Optional = Optional.ofNullable(action) fun isString(): Boolean = string != null @@ -657,7 +656,7 @@ private constructor( fun asString(): String = string.getOrThrow("string") /** Action object returned by observe and used by act */ - fun asAction(): ActionInput = action.getOrThrow("action") + fun asAction(): Action = action.getOrThrow("action") fun _json(): Optional = Optional.ofNullable(_json) @@ -679,7 +678,7 @@ private constructor( object : Visitor { override fun visitString(string: String) {} - override fun visitAction(action: ActionInput) { + override fun visitAction(action: Action) { action.validate() } } @@ -707,7 +706,7 @@ private constructor( object : Visitor { override fun visitString(string: String) = 1 - override fun visitAction(action: ActionInput) = action.validity() + override fun visitAction(action: Action) = action.validity() override fun unknown(json: JsonValue?) = 0 } @@ -736,7 +735,7 @@ private constructor( @JvmStatic fun ofString(string: String) = Input(string = string) /** Action object returned by observe and used by act */ - @JvmStatic fun ofAction(action: ActionInput) = Input(action = action) + @JvmStatic fun ofAction(action: Action) = Input(action = action) } /** An interface that defines how to map each variant of [Input] to a value of type [T]. */ @@ -745,7 +744,7 @@ private constructor( fun visitString(string: String): T /** Action object returned by observe and used by act */ - fun visitAction(action: ActionInput): T + fun visitAction(action: Action): T /** * Maps an unknown variant of [Input] to a value of type [T]. @@ -769,7 +768,7 @@ private constructor( val bestMatches = sequenceOf( - tryDeserialize(node, jacksonTypeRef())?.let { + tryDeserialize(node, jacksonTypeRef())?.let { Input(action = it, _json = json) }, tryDeserialize(node, jacksonTypeRef())?.let { @@ -807,311 +806,6 @@ private constructor( } } } - - /** Action object returned by observe and used by act */ - class ActionInput - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val description: JsonField, - private val selector: JsonField, - private val arguments: JsonField>, - private val method: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("description") - @ExcludeMissing - description: JsonField = JsonMissing.of(), - @JsonProperty("selector") - @ExcludeMissing - selector: JsonField = JsonMissing.of(), - @JsonProperty("arguments") - @ExcludeMissing - arguments: JsonField> = JsonMissing.of(), - @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), - ) : this(description, selector, arguments, method, mutableMapOf()) - - /** - * Human-readable description of the action - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun description(): String = description.getRequired("description") - - /** - * CSS selector or XPath for the element - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun selector(): String = selector.getRequired("selector") - - /** - * Arguments to pass to the method - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun arguments(): Optional> = arguments.getOptional("arguments") - - /** - * The method to execute (click, fill, etc.) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun method(): Optional = method.getOptional("method") - - /** - * Returns the raw JSON value of [description]. - * - * Unlike [description], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("description") - @ExcludeMissing - fun _description(): JsonField = description - - /** - * Returns the raw JSON value of [selector]. - * - * Unlike [selector], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector - - /** - * Returns the raw JSON value of [arguments]. - * - * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("arguments") - @ExcludeMissing - fun _arguments(): JsonField> = arguments - - /** - * Returns the raw JSON value of [method]. - * - * Unlike [method], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ActionInput]. - * - * The following fields are required: - * ```java - * .description() - * .selector() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ActionInput]. */ - class Builder internal constructor() { - - private var description: JsonField? = null - private var selector: JsonField? = null - private var arguments: JsonField>? = null - private var method: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(actionInput: ActionInput) = apply { - description = actionInput.description - selector = actionInput.selector - arguments = actionInput.arguments.map { it.toMutableList() } - method = actionInput.method - additionalProperties = actionInput.additionalProperties.toMutableMap() - } - - /** Human-readable description of the action */ - fun description(description: String) = description(JsonField.of(description)) - - /** - * Sets [Builder.description] to an arbitrary JSON value. - * - * You should usually call [Builder.description] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun description(description: JsonField) = apply { - this.description = description - } - - /** CSS selector or XPath for the element */ - fun selector(selector: String) = selector(JsonField.of(selector)) - - /** - * Sets [Builder.selector] to an arbitrary JSON value. - * - * You should usually call [Builder.selector] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun selector(selector: JsonField) = apply { this.selector = selector } - - /** Arguments to pass to the method */ - fun arguments(arguments: List) = arguments(JsonField.of(arguments)) - - /** - * Sets [Builder.arguments] to an arbitrary JSON value. - * - * You should usually call [Builder.arguments] with a well-typed `List` - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. - */ - fun arguments(arguments: JsonField>) = apply { - this.arguments = arguments.map { it.toMutableList() } - } - - /** - * Adds a single [String] to [arguments]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addArgument(argument: String) = apply { - arguments = - (arguments ?: JsonField.of(mutableListOf())).also { - checkKnown("arguments", it).add(argument) - } - } - - /** The method to execute (click, fill, etc.) */ - fun method(method: String) = method(JsonField.of(method)) - - /** - * Sets [Builder.method] to an arbitrary JSON value. - * - * You should usually call [Builder.method] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun method(method: JsonField) = apply { this.method = method } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [ActionInput]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .description() - * .selector() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ActionInput = - ActionInput( - checkRequired("description", description), - checkRequired("selector", selector), - (arguments ?: JsonMissing.of()).map { it.toImmutable() }, - method, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): ActionInput = apply { - if (validated) { - return@apply - } - - description() - selector() - arguments() - method() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (description.asKnown().isPresent) 1 else 0) + - (if (selector.asKnown().isPresent) 1 else 0) + - (arguments.asKnown().getOrNull()?.size ?: 0) + - (if (method.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ActionInput && - description == other.description && - selector == other.selector && - arguments == other.arguments && - method == other.method && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(description, selector, arguments, method, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "ActionInput{description=$description, selector=$selector, arguments=$arguments, method=$method, additionalProperties=$additionalProperties}" - } } class Options diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index b07cf2c..112be92 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -73,6 +73,14 @@ private constructor( */ fun options(): Optional = body.options() + /** + * Whether to stream the response via SSE + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun streamResponse(): Optional = body.streamResponse() + /** * Returns the raw JSON value of [url]. * @@ -94,6 +102,13 @@ private constructor( */ fun _options(): JsonField = body._options() + /** + * Returns the raw JSON value of [streamResponse]. + * + * Unlike [streamResponse], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _streamResponse(): JsonField = body._streamResponse() + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ @@ -182,6 +197,7 @@ private constructor( * - [url] * - [frameId] * - [options] + * - [streamResponse] */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -217,6 +233,20 @@ private constructor( */ fun options(options: JsonField) = apply { body.options(options) } + /** Whether to stream the response via SSE */ + fun streamResponse(streamResponse: Boolean) = apply { body.streamResponse(streamResponse) } + + /** + * Sets [Builder.streamResponse] to an arbitrary JSON value. + * + * You should usually call [Builder.streamResponse] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun streamResponse(streamResponse: JsonField) = apply { + body.streamResponse(streamResponse) + } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -386,6 +416,7 @@ private constructor( private val url: JsonField, private val frameId: JsonField, private val options: JsonField, + private val streamResponse: JsonField, private val additionalProperties: MutableMap, ) { @@ -394,7 +425,10 @@ private constructor( @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), @JsonProperty("options") @ExcludeMissing options: JsonField = JsonMissing.of(), - ) : this(url, frameId, options, mutableMapOf()) + @JsonProperty("streamResponse") + @ExcludeMissing + streamResponse: JsonField = JsonMissing.of(), + ) : this(url, frameId, options, streamResponse, mutableMapOf()) /** * URL to navigate to @@ -418,6 +452,14 @@ private constructor( */ fun options(): Optional = options.getOptional("options") + /** + * Whether to stream the response via SSE + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun streamResponse(): Optional = streamResponse.getOptional("streamResponse") + /** * Returns the raw JSON value of [url]. * @@ -439,6 +481,16 @@ private constructor( */ @JsonProperty("options") @ExcludeMissing fun _options(): JsonField = options + /** + * Returns the raw JSON value of [streamResponse]. + * + * Unlike [streamResponse], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("streamResponse") + @ExcludeMissing + fun _streamResponse(): JsonField = streamResponse + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -470,6 +522,7 @@ private constructor( private var url: JsonField? = null private var frameId: JsonField = JsonMissing.of() private var options: JsonField = JsonMissing.of() + private var streamResponse: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -477,6 +530,7 @@ private constructor( url = body.url frameId = body.frameId options = body.options + streamResponse = body.streamResponse additionalProperties = body.additionalProperties.toMutableMap() } @@ -515,6 +569,21 @@ private constructor( */ fun options(options: JsonField) = apply { this.options = options } + /** Whether to stream the response via SSE */ + fun streamResponse(streamResponse: Boolean) = + streamResponse(JsonField.of(streamResponse)) + + /** + * Sets [Builder.streamResponse] to an arbitrary JSON value. + * + * You should usually call [Builder.streamResponse] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun streamResponse(streamResponse: JsonField) = apply { + this.streamResponse = streamResponse + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -551,6 +620,7 @@ private constructor( checkRequired("url", url), frameId, options, + streamResponse, additionalProperties.toMutableMap(), ) } @@ -565,6 +635,7 @@ private constructor( url() frameId() options().ifPresent { it.validate() } + streamResponse() validated = true } @@ -586,7 +657,8 @@ private constructor( internal fun validity(): Int = (if (url.asKnown().isPresent) 1 else 0) + (if (frameId.asKnown().isPresent) 1 else 0) + - (options.asKnown().getOrNull()?.validity() ?: 0) + (options.asKnown().getOrNull()?.validity() ?: 0) + + (if (streamResponse.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -597,17 +669,18 @@ private constructor( url == other.url && frameId == other.frameId && options == other.options && + streamResponse == other.streamResponse && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(url, frameId, options, additionalProperties) + Objects.hash(url, frameId, options, streamResponse, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Body{url=$url, frameId=$frameId, options=$options, additionalProperties=$additionalProperties}" + "Body{url=$url, frameId=$frameId, options=$options, streamResponse=$streamResponse, additionalProperties=$additionalProperties}" } class Options diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index a172070..13ed630 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -192,6 +192,7 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val available: JsonField, + private val connectUrl: JsonField, private val sessionId: JsonField, private val additionalProperties: MutableMap, ) { @@ -201,10 +202,13 @@ private constructor( @JsonProperty("available") @ExcludeMissing available: JsonField = JsonMissing.of(), + @JsonProperty("connectUrl") + @ExcludeMissing + connectUrl: JsonField = JsonMissing.of(), @JsonProperty("sessionId") @ExcludeMissing sessionId: JsonField = JsonMissing.of(), - ) : this(available, sessionId, mutableMapOf()) + ) : this(available, connectUrl, sessionId, mutableMapOf()) /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is @@ -213,7 +217,15 @@ private constructor( fun available(): Boolean = available.getRequired("available") /** - * Unique session identifier + * CDP WebSocket URL for connecting to the Browserbase cloud browser + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun connectUrl(): String = connectUrl.getRequired("connectUrl") + + /** + * Unique Browserbase session identifier * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -227,6 +239,15 @@ private constructor( */ @JsonProperty("available") @ExcludeMissing fun _available(): JsonField = available + /** + * Returns the raw JSON value of [connectUrl]. + * + * Unlike [connectUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("connectUrl") + @ExcludeMissing + fun _connectUrl(): JsonField = connectUrl + /** * Returns the raw JSON value of [sessionId]. * @@ -254,6 +275,7 @@ private constructor( * The following fields are required: * ```java * .available() + * .connectUrl() * .sessionId() * ``` */ @@ -264,12 +286,14 @@ private constructor( class Builder internal constructor() { private var available: JsonField? = null + private var connectUrl: JsonField? = null private var sessionId: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(data: Data) = apply { available = data.available + connectUrl = data.connectUrl sessionId = data.sessionId additionalProperties = data.additionalProperties.toMutableMap() } @@ -285,7 +309,19 @@ private constructor( */ fun available(available: JsonField) = apply { this.available = available } - /** Unique session identifier */ + /** CDP WebSocket URL for connecting to the Browserbase cloud browser */ + fun connectUrl(connectUrl: String) = connectUrl(JsonField.of(connectUrl)) + + /** + * Sets [Builder.connectUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.connectUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun connectUrl(connectUrl: JsonField) = apply { this.connectUrl = connectUrl } + + /** Unique Browserbase session identifier */ fun sessionId(sessionId: String) = sessionId(JsonField.of(sessionId)) /** @@ -324,6 +360,7 @@ private constructor( * The following fields are required: * ```java * .available() + * .connectUrl() * .sessionId() * ``` * @@ -332,6 +369,7 @@ private constructor( fun build(): Data = Data( checkRequired("available", available), + checkRequired("connectUrl", connectUrl), checkRequired("sessionId", sessionId), additionalProperties.toMutableMap(), ) @@ -345,6 +383,7 @@ private constructor( } available() + connectUrl() sessionId() validated = true } @@ -366,6 +405,7 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (available.asKnown().isPresent) 1 else 0) + + (if (connectUrl.asKnown().isPresent) 1 else 0) + (if (sessionId.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -375,18 +415,19 @@ private constructor( return other is Data && available == other.available && + connectUrl == other.connectUrl && sessionId == other.sessionId && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(available, sessionId, additionalProperties) + Objects.hash(available, connectUrl, sessionId, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Data{available=$available, sessionId=$sessionId, additionalProperties=$additionalProperties}" + "Data{available=$available, connectUrl=$connectUrl, sessionId=$sessionId, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt new file mode 100644 index 0000000..d58dc3b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -0,0 +1,1175 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. */ +class StreamEvent +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val id: JsonField, + private val data: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(id, data, type, mutableMapOf()) + + /** + * Unique identifier for this event + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun id(): String = id.getRequired("id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * Type of stream event - system events or log messages + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun type(): Type = type.getRequired("type") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [StreamEvent]. + * + * The following fields are required: + * ```java + * .id() + * .data() + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [StreamEvent]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var data: JsonField? = null + private var type: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(streamEvent: StreamEvent) = apply { + id = streamEvent.id + data = streamEvent.data + type = streamEvent.type + additionalProperties = streamEvent.additionalProperties.toMutableMap() + } + + /** Unique identifier for this event */ + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + /** + * Alias for calling [data] with + * `Data.ofStreamEventSystemDataOutput(streamEventSystemDataOutput)`. + */ + fun data(streamEventSystemDataOutput: Data.StreamEventSystemDataOutput) = + data(Data.ofStreamEventSystemDataOutput(streamEventSystemDataOutput)) + + /** + * Alias for calling [data] with + * `Data.ofStreamEventLogDataOutput(streamEventLogDataOutput)`. + */ + fun data(streamEventLogDataOutput: Data.StreamEventLogDataOutput) = + data(Data.ofStreamEventLogDataOutput(streamEventLogDataOutput)) + + /** Type of stream event - system events or log messages */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [StreamEvent]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .data() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): StreamEvent = + StreamEvent( + checkRequired("id", id), + checkRequired("data", data), + checkRequired("type", type), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): StreamEvent = apply { + if (validated) { + return@apply + } + + id() + data().validate() + type().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (data.asKnown().getOrNull()?.validity() ?: 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + @JsonDeserialize(using = Data.Deserializer::class) + @JsonSerialize(using = Data.Serializer::class) + class Data + private constructor( + private val streamEventSystemDataOutput: StreamEventSystemDataOutput? = null, + private val streamEventLogDataOutput: StreamEventLogDataOutput? = null, + private val _json: JsonValue? = null, + ) { + + fun streamEventSystemDataOutput(): Optional = + Optional.ofNullable(streamEventSystemDataOutput) + + fun streamEventLogDataOutput(): Optional = + Optional.ofNullable(streamEventLogDataOutput) + + fun isStreamEventSystemDataOutput(): Boolean = streamEventSystemDataOutput != null + + fun isStreamEventLogDataOutput(): Boolean = streamEventLogDataOutput != null + + fun asStreamEventSystemDataOutput(): StreamEventSystemDataOutput = + streamEventSystemDataOutput.getOrThrow("streamEventSystemDataOutput") + + fun asStreamEventLogDataOutput(): StreamEventLogDataOutput = + streamEventLogDataOutput.getOrThrow("streamEventLogDataOutput") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + streamEventSystemDataOutput != null -> + visitor.visitStreamEventSystemDataOutput(streamEventSystemDataOutput) + streamEventLogDataOutput != null -> + visitor.visitStreamEventLogDataOutput(streamEventLogDataOutput) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitStreamEventSystemDataOutput( + streamEventSystemDataOutput: StreamEventSystemDataOutput + ) { + streamEventSystemDataOutput.validate() + } + + override fun visitStreamEventLogDataOutput( + streamEventLogDataOutput: StreamEventLogDataOutput + ) { + streamEventLogDataOutput.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitStreamEventSystemDataOutput( + streamEventSystemDataOutput: StreamEventSystemDataOutput + ) = streamEventSystemDataOutput.validity() + + override fun visitStreamEventLogDataOutput( + streamEventLogDataOutput: StreamEventLogDataOutput + ) = streamEventLogDataOutput.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + streamEventSystemDataOutput == other.streamEventSystemDataOutput && + streamEventLogDataOutput == other.streamEventLogDataOutput + } + + override fun hashCode(): Int = + Objects.hash(streamEventSystemDataOutput, streamEventLogDataOutput) + + override fun toString(): String = + when { + streamEventSystemDataOutput != null -> + "Data{streamEventSystemDataOutput=$streamEventSystemDataOutput}" + streamEventLogDataOutput != null -> + "Data{streamEventLogDataOutput=$streamEventLogDataOutput}" + _json != null -> "Data{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Data") + } + + companion object { + + @JvmStatic + fun ofStreamEventSystemDataOutput( + streamEventSystemDataOutput: StreamEventSystemDataOutput + ) = Data(streamEventSystemDataOutput = streamEventSystemDataOutput) + + @JvmStatic + fun ofStreamEventLogDataOutput(streamEventLogDataOutput: StreamEventLogDataOutput) = + Data(streamEventLogDataOutput = streamEventLogDataOutput) + } + + /** An interface that defines how to map each variant of [Data] to a value of type [T]. */ + interface Visitor { + + fun visitStreamEventSystemDataOutput( + streamEventSystemDataOutput: StreamEventSystemDataOutput + ): T + + fun visitStreamEventLogDataOutput(streamEventLogDataOutput: StreamEventLogDataOutput): T + + /** + * Maps an unknown variant of [Data] to a value of type [T]. + * + * An instance of [Data] can contain an unknown variant if it was deserialized from data + * that doesn't match any known variant. For example, if the SDK is on an older version + * than the API, then the API may respond with new variants that the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Data: $json") + } + } + + internal class Deserializer : BaseDeserializer(Data::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Data { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { Data(streamEventSystemDataOutput = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef())?.let { + Data(streamEventLogDataOutput = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> Data(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Data::class) { + + override fun serialize( + value: Data, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.streamEventSystemDataOutput != null -> + generator.writeObject(value.streamEventSystemDataOutput) + value.streamEventLogDataOutput != null -> + generator.writeObject(value.streamEventLogDataOutput) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Data") + } + } + } + + class StreamEventSystemDataOutput + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val status: JsonField, + private val error: JsonField, + private val result: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("status") + @ExcludeMissing + status: JsonField = JsonMissing.of(), + @JsonProperty("error") @ExcludeMissing error: JsonField = JsonMissing.of(), + @JsonProperty("result") @ExcludeMissing result: JsonValue = JsonMissing.of(), + ) : this(status, error, result, mutableMapOf()) + + /** + * Current status of the streaming operation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun status(): Status = status.getRequired("status") + + /** + * Error message (present when status is 'error') + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun error(): Optional = error.getOptional("error") + + /** Operation result (present when status is 'finished') */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonValue = result + + /** + * Returns the raw JSON value of [status]. + * + * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + + /** + * Returns the raw JSON value of [error]. + * + * Unlike [error], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("error") @ExcludeMissing fun _error(): JsonField = error + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [StreamEventSystemDataOutput]. + * + * The following fields are required: + * ```java + * .status() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [StreamEventSystemDataOutput]. */ + class Builder internal constructor() { + + private var status: JsonField? = null + private var error: JsonField = JsonMissing.of() + private var result: JsonValue = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(streamEventSystemDataOutput: StreamEventSystemDataOutput) = + apply { + status = streamEventSystemDataOutput.status + error = streamEventSystemDataOutput.error + result = streamEventSystemDataOutput.result + additionalProperties = + streamEventSystemDataOutput.additionalProperties.toMutableMap() + } + + /** Current status of the streaming operation */ + fun status(status: Status) = status(JsonField.of(status)) + + /** + * Sets [Builder.status] to an arbitrary JSON value. + * + * You should usually call [Builder.status] with a well-typed [Status] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun status(status: JsonField) = apply { this.status = status } + + /** Error message (present when status is 'error') */ + fun error(error: String) = error(JsonField.of(error)) + + /** + * Sets [Builder.error] to an arbitrary JSON value. + * + * You should usually call [Builder.error] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun error(error: JsonField) = apply { this.error = error } + + /** Operation result (present when status is 'finished') */ + fun result(result: JsonValue) = apply { this.result = result } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [StreamEventSystemDataOutput]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .status() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): StreamEventSystemDataOutput = + StreamEventSystemDataOutput( + checkRequired("status", status), + error, + result, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): StreamEventSystemDataOutput = apply { + if (validated) { + return@apply + } + + status().validate() + error() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (status.asKnown().getOrNull()?.validity() ?: 0) + + (if (error.asKnown().isPresent) 1 else 0) + + /** Current status of the streaming operation */ + class Status @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val STARTING = of("starting") + + @JvmField val CONNECTED = of("connected") + + @JvmField val RUNNING = of("running") + + @JvmField val FINISHED = of("finished") + + @JvmField val ERROR = of("error") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + STARTING, + CONNECTED, + RUNNING, + FINISHED, + ERROR, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + STARTING, + CONNECTED, + RUNNING, + FINISHED, + ERROR, + /** + * An enum member indicating that [Status] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + STARTING -> Value.STARTING + CONNECTED -> Value.CONNECTED + RUNNING -> Value.RUNNING + FINISHED -> Value.FINISHED + ERROR -> Value.ERROR + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + STARTING -> Known.STARTING + CONNECTED -> Known.CONNECTED + RUNNING -> Known.RUNNING + FINISHED -> Known.FINISHED + ERROR -> Known.ERROR + else -> throw StagehandInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StreamEventSystemDataOutput && + status == other.status && + error == other.error && + result == other.result && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(status, error, result, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "StreamEventSystemDataOutput{status=$status, error=$error, result=$result, additionalProperties=$additionalProperties}" + } + + class StreamEventLogDataOutput + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val message: JsonField, + private val status: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("message") + @ExcludeMissing + message: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + ) : this(message, status, mutableMapOf()) + + /** + * Log message from the operation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun message(): String = message.getRequired("message") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("running") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [StreamEventLogDataOutput]. + * + * The following fields are required: + * ```java + * .message() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [StreamEventLogDataOutput]. */ + class Builder internal constructor() { + + private var message: JsonField? = null + private var status: JsonValue = JsonValue.from("running") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(streamEventLogDataOutput: StreamEventLogDataOutput) = apply { + message = streamEventLogDataOutput.message + status = streamEventLogDataOutput.status + additionalProperties = + streamEventLogDataOutput.additionalProperties.toMutableMap() + } + + /** Log message from the operation */ + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("running") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [StreamEventLogDataOutput]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .message() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): StreamEventLogDataOutput = + StreamEventLogDataOutput( + checkRequired("message", message), + status, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): StreamEventLogDataOutput = apply { + if (validated) { + return@apply + } + + message() + _status().let { + if (it != JsonValue.from("running")) { + throw StagehandInvalidDataException("'status' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (message.asKnown().isPresent) 1 else 0) + + status.let { if (it == JsonValue.from("running")) 1 else 0 } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StreamEventLogDataOutput && + message == other.message && + status == other.status && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(message, status, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "StreamEventLogDataOutput{message=$message, status=$status, additionalProperties=$additionalProperties}" + } + } + + /** Type of stream event - system events or log messages */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val SYSTEM = of("system") + + @JvmField val LOG = of("log") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + SYSTEM, + LOG, + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + SYSTEM, + LOG, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + SYSTEM -> Value.SYSTEM + LOG -> Value.LOG + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + SYSTEM -> Known.SYSTEM + LOG -> Known.LOG + else -> throw StagehandInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Type && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StreamEvent && + id == other.id && + data == other.data && + type == other.type && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(id, data, type, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "StreamEvent{id=$id, data=$data, type=$type, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index 423fd57..5c9171e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -4,7 +4,9 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.core.http.StreamResponse import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse import com.browserbase.api.models.sessions.SessionEndParams @@ -19,6 +21,8 @@ import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse +import com.browserbase.api.models.sessions.StreamEvent +import com.google.errorprone.annotations.MustBeClosed import java.util.concurrent.CompletableFuture import java.util.function.Consumer @@ -60,6 +64,30 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** + * Executes a browser action using natural language instructions or a predefined Action object. + */ + fun actStreaming(id: String, params: SessionActParams): AsyncStreamResponse = + actStreaming(id, params, RequestOptions.none()) + + /** @see actStreaming */ + fun actStreaming( + id: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse = + actStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see actStreaming */ + fun actStreaming(params: SessionActParams): AsyncStreamResponse = + actStreaming(params, RequestOptions.none()) + + /** @see actStreaming */ + fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse + /** Terminates the browser session and releases all associated resources. */ fun end(id: String): CompletableFuture = end(id, SessionEndParams.none()) @@ -115,6 +143,30 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ + fun executeStreaming( + id: String, + params: SessionExecuteParams, + ): AsyncStreamResponse = executeStreaming(id, params, RequestOptions.none()) + + /** @see executeStreaming */ + fun executeStreaming( + id: String, + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse = + executeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeStreaming */ + fun executeStreaming(params: SessionExecuteParams): AsyncStreamResponse = + executeStreaming(params, RequestOptions.none()) + + /** @see executeStreaming */ + fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse + /** Extracts structured data from the current page using AI-powered analysis. */ fun extract(id: String): CompletableFuture = extract(id, SessionExtractParams.none()) @@ -150,6 +202,41 @@ interface SessionServiceAsync { ): CompletableFuture = extract(id, SessionExtractParams.none(), requestOptions) + /** Extracts structured data from the current page using AI-powered analysis. */ + fun extractStreaming(id: String): AsyncStreamResponse = + extractStreaming(id, SessionExtractParams.none()) + + /** @see extractStreaming */ + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse = + extractStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see extractStreaming */ + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): AsyncStreamResponse = extractStreaming(id, params, RequestOptions.none()) + + /** @see extractStreaming */ + fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse + + /** @see extractStreaming */ + fun extractStreaming(params: SessionExtractParams): AsyncStreamResponse = + extractStreaming(params, RequestOptions.none()) + + /** @see extractStreaming */ + fun extractStreaming( + id: String, + requestOptions: RequestOptions, + ): AsyncStreamResponse = + extractStreaming(id, SessionExtractParams.none(), requestOptions) + /** Navigates the browser to the specified URL. */ fun navigate( id: String, @@ -212,6 +299,44 @@ interface SessionServiceAsync { ): CompletableFuture = observe(id, SessionObserveParams.none(), requestOptions) + /** + * Identifies and returns available actions on the current page that match the given + * instruction. + */ + fun observeStreaming(id: String): AsyncStreamResponse = + observeStreaming(id, SessionObserveParams.none()) + + /** @see observeStreaming */ + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse = + observeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see observeStreaming */ + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): AsyncStreamResponse = observeStreaming(id, params, RequestOptions.none()) + + /** @see observeStreaming */ + fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse + + /** @see observeStreaming */ + fun observeStreaming(params: SessionObserveParams): AsyncStreamResponse = + observeStreaming(params, RequestOptions.none()) + + /** @see observeStreaming */ + fun observeStreaming( + id: String, + requestOptions: RequestOptions, + ): AsyncStreamResponse = + observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. @@ -267,6 +392,40 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/act`, but is otherwise the same + * as [SessionServiceAsync.actStreaming]. + */ + @MustBeClosed + fun actStreaming( + id: String, + params: SessionActParams, + ): CompletableFuture>> = + actStreaming(id, params, RequestOptions.none()) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + id: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + actStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + params: SessionActParams + ): CompletableFuture>> = + actStreaming(params, RequestOptions.none()) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/end`, but is otherwise the same * as [SessionServiceAsync.end]. @@ -336,6 +495,40 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise + * the same as [SessionServiceAsync.executeStreaming]. + */ + @MustBeClosed + fun executeStreaming( + id: String, + params: SessionExecuteParams, + ): CompletableFuture>> = + executeStreaming(id, params, RequestOptions.none()) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + id: String, + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + executeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + params: SessionExecuteParams + ): CompletableFuture>> = + executeStreaming(params, RequestOptions.none()) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/extract`, but is otherwise the * same as [SessionServiceAsync.extract]. @@ -377,6 +570,55 @@ interface SessionServiceAsync { ): CompletableFuture> = extract(id, SessionExtractParams.none(), requestOptions) + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/extract`, but is otherwise the + * same as [SessionServiceAsync.extractStreaming]. + */ + @MustBeClosed + fun extractStreaming( + id: String + ): CompletableFuture>> = + extractStreaming(id, SessionExtractParams.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + extractStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): CompletableFuture>> = + extractStreaming(id, params, RequestOptions.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + params: SessionExtractParams + ): CompletableFuture>> = + extractStreaming(params, RequestOptions.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture>> = + extractStreaming(id, SessionExtractParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/navigate`, but is otherwise the * same as [SessionServiceAsync.navigate]. @@ -448,6 +690,55 @@ interface SessionServiceAsync { ): CompletableFuture> = observe(id, SessionObserveParams.none(), requestOptions) + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/observe`, but is otherwise the + * same as [SessionServiceAsync.observeStreaming]. + */ + @MustBeClosed + fun observeStreaming( + id: String + ): CompletableFuture>> = + observeStreaming(id, SessionObserveParams.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + observeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): CompletableFuture>> = + observeStreaming(id, params, RequestOptions.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + params: SessionObserveParams + ): CompletableFuture>> = + observeStreaming(params, RequestOptions.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture>> = + observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/start`, but is otherwise the same as * [SessionServiceAsync.start]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 99037bc..82062e4 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -3,18 +3,25 @@ package com.browserbase.api.services.async import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.checkRequired import com.browserbase.api.core.handlers.errorBodyHandler import com.browserbase.api.core.handlers.errorHandler import com.browserbase.api.core.handlers.jsonHandler +import com.browserbase.api.core.handlers.mapJson +import com.browserbase.api.core.handlers.sseHandler +import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.HttpMethod import com.browserbase.api.core.http.HttpRequest import com.browserbase.api.core.http.HttpResponse import com.browserbase.api.core.http.HttpResponse.Handler import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.core.http.StreamResponse import com.browserbase.api.core.http.json +import com.browserbase.api.core.http.map import com.browserbase.api.core.http.parseable +import com.browserbase.api.core.http.toAsync import com.browserbase.api.core.prepareAsync import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse @@ -30,6 +37,7 @@ import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse +import com.browserbase.api.models.sessions.StreamEvent import java.util.concurrent.CompletableFuture import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull @@ -53,6 +61,16 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl // post /v1/sessions/{id}/act withRawResponse().act(params, requestOptions).thenApply { it.parse() } + override fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions, + ): AsyncStreamResponse = + // post /v1/sessions/{id}/act + withRawResponse() + .actStreaming(params, requestOptions) + .thenApply { it.parse() } + .toAsync(clientOptions.streamHandlerExecutor) + override fun end( params: SessionEndParams, requestOptions: RequestOptions, @@ -67,6 +85,16 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl // post /v1/sessions/{id}/agentExecute withRawResponse().execute(params, requestOptions).thenApply { it.parse() } + override fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions, + ): AsyncStreamResponse = + // post /v1/sessions/{id}/agentExecute + withRawResponse() + .executeStreaming(params, requestOptions) + .thenApply { it.parse() } + .toAsync(clientOptions.streamHandlerExecutor) + override fun extract( params: SessionExtractParams, requestOptions: RequestOptions, @@ -74,6 +102,16 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl // post /v1/sessions/{id}/extract withRawResponse().extract(params, requestOptions).thenApply { it.parse() } + override fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): AsyncStreamResponse = + // post /v1/sessions/{id}/extract + withRawResponse() + .extractStreaming(params, requestOptions) + .thenApply { it.parse() } + .toAsync(clientOptions.streamHandlerExecutor) + override fun navigate( params: SessionNavigateParams, requestOptions: RequestOptions, @@ -88,6 +126,16 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl // post /v1/sessions/{id}/observe withRawResponse().observe(params, requestOptions).thenApply { it.parse() } + override fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): AsyncStreamResponse = + // post /v1/sessions/{id}/observe + withRawResponse() + .observeStreaming(params, requestOptions) + .thenApply { it.parse() } + .toAsync(clientOptions.streamHandlerExecutor) + override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -142,6 +190,51 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl } } + private val actStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions, + ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "act") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .let { actStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + } + private val endHandler: Handler = jsonHandler(clientOptions.jsonMapper) @@ -210,6 +303,51 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl } } + private val executeStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions, + ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "agentExecute") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .let { executeStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + } + private val extractHandler: Handler = jsonHandler(clientOptions.jsonMapper) @@ -244,6 +382,51 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl } } + private val extractStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "extract") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .let { extractStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + } + private val navigateHandler: Handler = jsonHandler(clientOptions.jsonMapper) @@ -312,6 +495,51 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl } } + private val observeStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "observe") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .let { observeStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + } + private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index df7bb72..0d56e93 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -5,6 +5,7 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.core.http.StreamResponse import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionActResponse import com.browserbase.api.models.sessions.SessionEndParams @@ -19,6 +20,7 @@ import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse +import com.browserbase.api.models.sessions.StreamEvent import com.google.errorprone.annotations.MustBeClosed import java.util.function.Consumer @@ -58,6 +60,33 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): SessionActResponse + /** + * Executes a browser action using natural language instructions or a predefined Action object. + */ + @MustBeClosed + fun actStreaming(id: String, params: SessionActParams): StreamResponse = + actStreaming(id, params, RequestOptions.none()) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + id: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse = actStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming(params: SessionActParams): StreamResponse = + actStreaming(params, RequestOptions.none()) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse + /** Terminates the browser session and releases all associated resources. */ fun end(id: String): SessionEndResponse = end(id, SessionEndParams.none()) @@ -106,6 +135,32 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): SessionExecuteResponse + /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ + @MustBeClosed + fun executeStreaming(id: String, params: SessionExecuteParams): StreamResponse = + executeStreaming(id, params, RequestOptions.none()) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + id: String, + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse = + executeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming(params: SessionExecuteParams): StreamResponse = + executeStreaming(params, RequestOptions.none()) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse + /** Extracts structured data from the current page using AI-powered analysis. */ fun extract(id: String): SessionExtractResponse = extract(id, SessionExtractParams.none()) @@ -136,6 +191,44 @@ interface SessionService { fun extract(id: String, requestOptions: RequestOptions): SessionExtractResponse = extract(id, SessionExtractParams.none(), requestOptions) + /** Extracts structured data from the current page using AI-powered analysis. */ + @MustBeClosed + fun extractStreaming(id: String): StreamResponse = + extractStreaming(id, SessionExtractParams.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse = + extractStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): StreamResponse = extractStreaming(id, params, RequestOptions.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming(params: SessionExtractParams): StreamResponse = + extractStreaming(params, RequestOptions.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming(id: String, requestOptions: RequestOptions): StreamResponse = + extractStreaming(id, SessionExtractParams.none(), requestOptions) + /** Navigates the browser to the specified URL. */ fun navigate(id: String, params: SessionNavigateParams): SessionNavigateResponse = navigate(id, params, RequestOptions.none()) @@ -190,6 +283,47 @@ interface SessionService { fun observe(id: String, requestOptions: RequestOptions): SessionObserveResponse = observe(id, SessionObserveParams.none(), requestOptions) + /** + * Identifies and returns available actions on the current page that match the given + * instruction. + */ + @MustBeClosed + fun observeStreaming(id: String): StreamResponse = + observeStreaming(id, SessionObserveParams.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse = + observeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): StreamResponse = observeStreaming(id, params, RequestOptions.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming(params: SessionObserveParams): StreamResponse = + observeStreaming(params, RequestOptions.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming(id: String, requestOptions: RequestOptions): StreamResponse = + observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. @@ -242,6 +376,38 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/act`, but is otherwise the same + * as [SessionService.actStreaming]. + */ + @MustBeClosed + fun actStreaming( + id: String, + params: SessionActParams, + ): HttpResponseFor> = + actStreaming(id, params, RequestOptions.none()) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + id: String, + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + actStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming(params: SessionActParams): HttpResponseFor> = + actStreaming(params, RequestOptions.none()) + + /** @see actStreaming */ + @MustBeClosed + fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/end`, but is otherwise the same * as [SessionService.end]. @@ -313,6 +479,40 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise + * the same as [SessionService.executeStreaming]. + */ + @MustBeClosed + fun executeStreaming( + id: String, + params: SessionExecuteParams, + ): HttpResponseFor> = + executeStreaming(id, params, RequestOptions.none()) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + id: String, + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + executeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + params: SessionExecuteParams + ): HttpResponseFor> = + executeStreaming(params, RequestOptions.none()) + + /** @see executeStreaming */ + @MustBeClosed + fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/extract`, but is otherwise the * same as [SessionService.extract]. @@ -357,6 +557,53 @@ interface SessionService { ): HttpResponseFor = extract(id, SessionExtractParams.none(), requestOptions) + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/extract`, but is otherwise the + * same as [SessionService.extractStreaming]. + */ + @MustBeClosed + fun extractStreaming(id: String): HttpResponseFor> = + extractStreaming(id, SessionExtractParams.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + extractStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + params: SessionExtractParams = SessionExtractParams.none(), + ): HttpResponseFor> = + extractStreaming(id, params, RequestOptions.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + params: SessionExtractParams + ): HttpResponseFor> = + extractStreaming(params, RequestOptions.none()) + + /** @see extractStreaming */ + @MustBeClosed + fun extractStreaming( + id: String, + requestOptions: RequestOptions, + ): HttpResponseFor> = + extractStreaming(id, SessionExtractParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/navigate`, but is otherwise the * same as [SessionService.navigate]. @@ -432,6 +679,53 @@ interface SessionService { ): HttpResponseFor = observe(id, SessionObserveParams.none(), requestOptions) + /** + * Returns a raw HTTP response for `post /v1/sessions/{id}/observe`, but is otherwise the + * same as [SessionService.observeStreaming]. + */ + @MustBeClosed + fun observeStreaming(id: String): HttpResponseFor> = + observeStreaming(id, SessionObserveParams.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + observeStreaming(params.toBuilder().id(id).build(), requestOptions) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + params: SessionObserveParams = SessionObserveParams.none(), + ): HttpResponseFor> = + observeStreaming(id, params, RequestOptions.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + params: SessionObserveParams + ): HttpResponseFor> = + observeStreaming(params, RequestOptions.none()) + + /** @see observeStreaming */ + @MustBeClosed + fun observeStreaming( + id: String, + requestOptions: RequestOptions, + ): HttpResponseFor> = + observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/start`, but is otherwise the same as * [SessionService.start]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index aac8272..4bfce1b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -3,17 +3,22 @@ package com.browserbase.api.services.blocking import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.checkRequired import com.browserbase.api.core.handlers.errorBodyHandler import com.browserbase.api.core.handlers.errorHandler import com.browserbase.api.core.handlers.jsonHandler +import com.browserbase.api.core.handlers.mapJson +import com.browserbase.api.core.handlers.sseHandler import com.browserbase.api.core.http.HttpMethod import com.browserbase.api.core.http.HttpRequest import com.browserbase.api.core.http.HttpResponse import com.browserbase.api.core.http.HttpResponse.Handler import com.browserbase.api.core.http.HttpResponseFor +import com.browserbase.api.core.http.StreamResponse import com.browserbase.api.core.http.json +import com.browserbase.api.core.http.map import com.browserbase.api.core.http.parseable import com.browserbase.api.core.prepare import com.browserbase.api.models.sessions.SessionActParams @@ -30,6 +35,7 @@ import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse +import com.browserbase.api.models.sessions.StreamEvent import java.util.function.Consumer import kotlin.jvm.optionals.getOrNull @@ -49,6 +55,13 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO // post /v1/sessions/{id}/act withRawResponse().act(params, requestOptions).parse() + override fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions, + ): StreamResponse = + // post /v1/sessions/{id}/act + withRawResponse().actStreaming(params, requestOptions).parse() + override fun end(params: SessionEndParams, requestOptions: RequestOptions): SessionEndResponse = // post /v1/sessions/{id}/end withRawResponse().end(params, requestOptions).parse() @@ -60,6 +73,13 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO // post /v1/sessions/{id}/agentExecute withRawResponse().execute(params, requestOptions).parse() + override fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions, + ): StreamResponse = + // post /v1/sessions/{id}/agentExecute + withRawResponse().executeStreaming(params, requestOptions).parse() + override fun extract( params: SessionExtractParams, requestOptions: RequestOptions, @@ -67,6 +87,13 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO // post /v1/sessions/{id}/extract withRawResponse().extract(params, requestOptions).parse() + override fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): StreamResponse = + // post /v1/sessions/{id}/extract + withRawResponse().extractStreaming(params, requestOptions).parse() + override fun navigate( params: SessionNavigateParams, requestOptions: RequestOptions, @@ -81,6 +108,13 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO // post /v1/sessions/{id}/observe withRawResponse().observe(params, requestOptions).parse() + override fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): StreamResponse = + // post /v1/sessions/{id}/observe + withRawResponse().observeStreaming(params, requestOptions).parse() + override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -132,6 +166,48 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO } } + private val actStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun actStreaming( + params: SessionActParams, + requestOptions: RequestOptions, + ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "act") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .let { actStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + private val endHandler: Handler = jsonHandler(clientOptions.jsonMapper) @@ -194,6 +270,48 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO } } + private val executeStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun executeStreaming( + params: SessionExecuteParams, + requestOptions: RequestOptions, + ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "agentExecute") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .let { executeStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + private val extractHandler: Handler = jsonHandler(clientOptions.jsonMapper) @@ -225,6 +343,48 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO } } + private val extractStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun extractStreaming( + params: SessionExtractParams, + requestOptions: RequestOptions, + ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "extract") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .let { extractStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + private val navigateHandler: Handler = jsonHandler(clientOptions.jsonMapper) @@ -287,6 +447,48 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO } } + private val observeStreamingHandler: Handler> = + sseHandler(clientOptions.jsonMapper).mapJson() + + override fun observeStreaming( + params: SessionObserveParams, + requestOptions: RequestOptions, + ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "observe") + .body( + json( + clientOptions.jsonMapper, + params + ._body() + .toBuilder() + .putAdditionalProperty("streamResponse", JsonValue.from(true)) + .build(), + ) + ) + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .let { observeStreamingHandler.handle(it) } + .let { streamResponse -> + if (requestOptions.responseValidation!!) { + streamResponse.map { it.validate() } + } else { + streamResponse + } + } + } + } + private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt new file mode 100644 index 0000000..29105f3 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt @@ -0,0 +1,134 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.core.handlers + +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.SseMessage +import com.browserbase.api.core.jsonMapper +import java.io.InputStream +import java.util.stream.Collectors.toList +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.catchThrowable +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class SseHandlerTest { + + enum class TestCase( + internal val body: String, + internal val expectedMessages: List? = null, + internal val expectedException: Exception? = null, + ) { + DATA_MISSING_EVENT( + buildString { + append("data: {\"foo\":true}\n") + append("\n") + }, + listOf(sseMessageBuilder().data("{\"foo\":true}").build()), + ), + MULTIPLE_DATA_MISSING_EVENT( + buildString { + append("data: {\"foo\":true}\n") + append("\n") + append("data: {\"bar\":false}\n") + append("\n") + }, + listOf( + sseMessageBuilder().data("{\"foo\":true}").build(), + sseMessageBuilder().data("{\"bar\":false}").build(), + ), + ), + DATA_JSON_ESCAPED_DOUBLE_NEW_LINE( + buildString { + append("data: {\n") + append("data: \"foo\":\n") + append("data: true}\n") + append("\n\n") + }, + listOf(sseMessageBuilder().data("{\n\"foo\":\ntrue}").build()), + ), + MULTIPLE_DATA_LINES( + buildString { + append("data: {\n") + append("data: \"foo\":\n") + append("data: true}\n") + append("\n\n") + }, + listOf(sseMessageBuilder().data("{\n\"foo\":\ntrue}").build()), + ), + SPECIAL_NEW_LINE_CHARACTER( + buildString { + append("data: {\"content\":\" culpa\"}\n") + append("\n") + append("data: {\"content\":\" \u2028\"}\n") + append("\n") + append("data: {\"content\":\"foo\"}\n") + append("\n") + }, + listOf( + sseMessageBuilder().data("{\"content\":\" culpa\"}").build(), + sseMessageBuilder().data("{\"content\":\" \u2028\"}").build(), + sseMessageBuilder().data("{\"content\":\"foo\"}").build(), + ), + ), + MULTI_BYTE_CHARACTER( + buildString { + append("data: {\"content\":\"\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0438\"}\n") + append("\n") + }, + listOf(sseMessageBuilder().data("{\"content\":\"известни\"}").build()), + ), + } + + @ParameterizedTest + @EnumSource + fun handle(testCase: TestCase) { + val response = httpResponse(testCase.body) + var messages: List? = null + var exception: Exception? = null + + try { + messages = + sseHandler(jsonMapper()).handle(response).use { it.stream().collect(toList()) } + } catch (e: Exception) { + exception = e + } + + if (testCase.expectedMessages != null) { + assertThat(messages).containsExactlyElementsOf(testCase.expectedMessages) + } + if (testCase.expectedException != null) { + assertThat(exception).isInstanceOf(testCase.expectedException.javaClass) + assertThat(exception).hasMessage(testCase.expectedException.message) + } + } + + @Test + fun cannotReuseStream() { + val response = httpResponse("body") + val streamResponse = sseHandler(jsonMapper()).handle(response) + + val throwable = + streamResponse.use { + it.stream().collect(toList()) + catchThrowable { it.stream().collect(toList()) } + } + + assertThat(throwable).isInstanceOf(IllegalStateException::class.java) + } +} + +private fun httpResponse(body: String): HttpResponse = + object : HttpResponse { + override fun statusCode(): Int = 0 + + override fun headers(): Headers = Headers.builder().build() + + override fun body(): InputStream = body.toByteArray().inputStream() + + override fun close() {} + } + +private fun sseMessageBuilder() = SseMessage.builder().jsonMapper(jsonMapper()) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/StreamHandlerTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/StreamHandlerTest.kt new file mode 100644 index 0000000..7da5378 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/StreamHandlerTest.kt @@ -0,0 +1,94 @@ +package com.browserbase.api.core.handlers + +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.errors.StagehandIoException +import java.io.IOException +import java.io.InputStream +import kotlin.streams.asSequence +import kotlin.test.Test +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.assertThrows + +internal class StreamHandlerTest { + + @Test + fun streamHandler_splitsStreamOnNewlines() { + val handler = streamHandler { _, lines -> yieldAll(lines) } + val streamResponse = handler.handle(httpResponse("a\nbb\nccc\ndddd".byteInputStream())) + + val lines = streamResponse.stream().asSequence().toList() + + assertThat(lines).containsExactly("a", "bb", "ccc", "dddd") + } + + @Test + fun streamHandler_whenClosedEarly_stopsYielding() { + val handler = streamHandler { _, lines -> yieldAll(lines) } + val streamResponse = handler.handle(httpResponse("a\nbb\nccc\ndddd".byteInputStream())) + + val lines = + streamResponse + .stream() + .asSequence() + .onEach { + if (it == "bb") { + streamResponse.close() + } + } + .toList() + + assertThat(lines).containsExactly("a", "bb") + } + + @Test + fun streamHandler_whenReaderThrowsIOException_wrapsException() { + val handler = streamHandler { _, lines -> lines.forEach {} } + val streamResponse = handler.handle(httpResponse("a\nb\nc\n".byteInputStream().throwing())) + + val e = assertThrows { streamResponse.stream().forEach {} } + assertThat(e).hasMessage("Stream failed") + assertThat(e).hasCauseInstanceOf(IOException::class.java) + } + + @Test + fun streamHandler_whenBlockThrowsIOException_doesNotWrapException() { + val ioException = IOException("BOOM!") + val handler = + streamHandler { _, lines -> + lines.forEachIndexed { index, _ -> + if (index == 2) { + throw ioException + } + } + } + val streamResponse = handler.handle(httpResponse("a\nb\nc\n".byteInputStream())) + + val e = assertThrows { streamResponse.stream().forEach {} } + assertThat(e).isSameAs(ioException) + } + + private fun httpResponse(body: InputStream): HttpResponse = + object : HttpResponse { + + override fun statusCode(): Int = 0 + + override fun headers(): Headers = Headers.builder().build() + + override fun body(): InputStream = body + + override fun close() {} + } + + private fun InputStream.throwing(): InputStream = + object : InputStream() { + + override fun read(): Int { + val byte = this@throwing.read() + if (byte == -1) { + throw IOException("BOOM!") + } + return byte + } + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt index 3bba7d4..169d089 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -26,6 +26,7 @@ internal class SessionNavigateParamsTest { .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) .build() ) + .streamResponse(true) .build() } @@ -60,6 +61,7 @@ internal class SessionNavigateParamsTest { .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) .build() ) + .streamResponse(true) .build() val headers = params._headers() @@ -106,6 +108,7 @@ internal class SessionNavigateParamsTest { .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) .build() ) + .streamResponse(true) .build() val body = params._body() @@ -120,6 +123,7 @@ internal class SessionNavigateParamsTest { .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) .build() ) + assertThat(body.streamResponse()).contains(true) } @Test diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt index 3af1696..4a712ec 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt @@ -16,6 +16,7 @@ internal class SessionStartResponseTest { .data( SessionStartResponse.Data.builder() .available(true) + .connectUrl("wss://connect.browserbase.com/?signingKey=abc123") .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .build() ) @@ -26,6 +27,7 @@ internal class SessionStartResponseTest { .isEqualTo( SessionStartResponse.Data.builder() .available(true) + .connectUrl("wss://connect.browserbase.com/?signingKey=abc123") .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .build() ) @@ -40,6 +42,7 @@ internal class SessionStartResponseTest { .data( SessionStartResponse.Data.builder() .available(true) + .connectUrl("wss://connect.browserbase.com/?signingKey=abc123") .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/StreamEventTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/StreamEventTest.kt new file mode 100644 index 0000000..9d58bf8 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/StreamEventTest.kt @@ -0,0 +1,66 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class StreamEventTest { + + @Test + fun create() { + val streamEvent = + StreamEvent.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .data( + StreamEvent.Data.StreamEventSystemDataOutput.builder() + .status(StreamEvent.Data.StreamEventSystemDataOutput.Status.STARTING) + .error("error") + .result(JsonValue.from(mapOf())) + .build() + ) + .type(StreamEvent.Type.SYSTEM) + .build() + + assertThat(streamEvent.id()).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + assertThat(streamEvent.data()) + .isEqualTo( + StreamEvent.Data.ofStreamEventSystemDataOutput( + StreamEvent.Data.StreamEventSystemDataOutput.builder() + .status(StreamEvent.Data.StreamEventSystemDataOutput.Status.STARTING) + .error("error") + .result(JsonValue.from(mapOf())) + .build() + ) + ) + assertThat(streamEvent.type()).isEqualTo(StreamEvent.Type.SYSTEM) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val streamEvent = + StreamEvent.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .data( + StreamEvent.Data.StreamEventSystemDataOutput.builder() + .status(StreamEvent.Data.StreamEventSystemDataOutput.Status.STARTING) + .error("error") + .result(JsonValue.from(mapOf())) + .build() + ) + .type(StreamEvent.Type.SYSTEM) + .build() + + val roundtrippedStreamEvent = + jsonMapper.readValue( + jsonMapper.writeValueAsString(streamEvent), + jacksonTypeRef(), + ) + + assertThat(roundtrippedStreamEvent).isEqualTo(streamEvent) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 270a06b..78ba6e7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -60,6 +60,47 @@ internal class SessionServiceAsyncTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun actStreaming() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseStreamResponse = + sessionServiceAsync.actStreaming( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("openai/gpt-5-nano") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) + .build() + ) + + val onCompleteFuture = + responseStreamResponse.subscribe { response -> response.validate() }.onCompleteFuture() + onCompleteFuture.get() + } + @Disabled("Prism tests are disabled") @Test fun end() { @@ -131,6 +172,51 @@ internal class SessionServiceAsyncTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun executeStreaming() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseStreamResponse = + sessionServiceAsync.executeStreaming( + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-5-nano") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") + .build() + ) + + val onCompleteFuture = + responseStreamResponse.subscribe { response -> response.validate() }.onCompleteFuture() + onCompleteFuture.get() + } + @Disabled("Prism tests are disabled") @Test fun extract() { @@ -172,6 +258,48 @@ internal class SessionServiceAsyncTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun extractStreaming() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseStreamResponse = + sessionServiceAsync.extractStreaming( + SessionExtractParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("openai/gpt-5-nano") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + + val onCompleteFuture = + responseStreamResponse.subscribe { response -> response.validate() }.onCompleteFuture() + onCompleteFuture.get() + } + @Disabled("Prism tests are disabled") @Test fun navigate() { @@ -201,6 +329,7 @@ internal class SessionServiceAsyncTest { .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) .build() ) + .streamResponse(true) .build() ) @@ -244,6 +373,43 @@ internal class SessionServiceAsyncTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun observeStreaming() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseStreamResponse = + sessionServiceAsync.observeStreaming( + SessionObserveParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("openai/gpt-5-nano") + .selector("nav") + .timeout(30000.0) + .build() + ) + .build() + ) + + val onCompleteFuture = + responseStreamResponse.subscribe { response -> response.validate() }.onCompleteFuture() + onCompleteFuture.get() + } + @Disabled("Prism tests are disabled") @Test fun start() { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index af06455..3355c14 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -59,6 +59,47 @@ internal class SessionServiceTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun actStreaming() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val responseStreamResponse = + sessionService.actStreaming( + SessionActParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionActParams.XStreamResponse.TRUE) + .input("Click the login button") + .frameId("frameId") + .options( + SessionActParams.Options.builder() + .model("openai/gpt-5-nano") + .timeout(30000.0) + .variables( + SessionActParams.Options.Variables.builder() + .putAdditionalProperty("username", JsonValue.from("john_doe")) + .build() + ) + .build() + ) + .build() + ) + + responseStreamResponse.use { + responseStreamResponse.stream().forEach { response -> response.validate() } + } + } + @Disabled("Prism tests are disabled") @Test fun end() { @@ -128,6 +169,51 @@ internal class SessionServiceTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun executeStreaming() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val responseStreamResponse = + sessionService.executeStreaming( + SessionExecuteParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) + .agentConfig( + SessionExecuteParams.AgentConfig.builder() + .cua(true) + .model("openai/gpt-5-nano") + .systemPrompt("systemPrompt") + .build() + ) + .executeOptions( + SessionExecuteParams.ExecuteOptions.builder() + .instruction( + "Log in with username 'demo' and password 'test123', then navigate to settings" + ) + .highlightCursor(true) + .maxSteps(20.0) + .build() + ) + .frameId("frameId") + .build() + ) + + responseStreamResponse.use { + responseStreamResponse.stream().forEach { response -> response.validate() } + } + } + @Disabled("Prism tests are disabled") @Test fun extract() { @@ -168,6 +254,48 @@ internal class SessionServiceTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun extractStreaming() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val responseStreamResponse = + sessionService.extractStreaming( + SessionExtractParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Extract all product names and prices from the page") + .options( + SessionExtractParams.Options.builder() + .model("openai/gpt-5-nano") + .selector("#main-content") + .timeout(30000.0) + .build() + ) + .schema( + SessionExtractParams.Schema.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + ) + + responseStreamResponse.use { + responseStreamResponse.stream().forEach { response -> response.validate() } + } + } + @Disabled("Prism tests are disabled") @Test fun navigate() { @@ -197,6 +325,7 @@ internal class SessionServiceTest { .waitUntil(SessionNavigateParams.Options.WaitUntil.NETWORKIDLE) .build() ) + .streamResponse(true) .build() ) @@ -238,6 +367,43 @@ internal class SessionServiceTest { response.validate() } + @Disabled("Prism tests are disabled") + @Test + fun observeStreaming() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val responseStreamResponse = + sessionService.observeStreaming( + SessionObserveParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) + .frameId("frameId") + .instruction("Find all clickable navigation links") + .options( + SessionObserveParams.Options.builder() + .model("openai/gpt-5-nano") + .selector("nav") + .timeout(30000.0) + .build() + ) + .build() + ) + + responseStreamResponse.use { + responseStreamResponse.stream().forEach { response -> response.validate() } + } + } + @Disabled("Prism tests are disabled") @Test fun start() { From 40b6c5274ee25f2e79ae8cbb82350555b7c80432 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 23:35:48 +0000 Subject: [PATCH 038/164] feat(api): manual updates --- .stats.yml | 4 +- .../browserbase/api/models/sessions/Action.kt | 47 ++- .../api/models/sessions/ModelConfig.kt | 190 ++++++++- .../api/models/sessions/SessionActResponse.kt | 360 +++++++++++++++++ .../models/sessions/SessionExecuteParams.kt | 187 ++++++++- .../models/sessions/SessionObserveResponse.kt | 375 +++++++++++++++++- .../api/models/sessions/SessionStartParams.kt | 240 +++++++---- .../models/sessions/SessionStartResponse.kt | 84 ++-- .../api/models/sessions/StreamEvent.kt | 5 +- .../api/models/sessions/ActionTest.kt | 3 + .../api/models/sessions/ModelConfigTest.kt | 2 + .../models/sessions/SessionActResponseTest.kt | 9 +- .../sessions/SessionExecuteParamsTest.kt | 4 + .../sessions/SessionObserveResponseTest.kt | 9 +- .../models/sessions/SessionStartParamsTest.kt | 20 +- .../sessions/SessionStartResponseTest.kt | 6 +- .../api/services/ErrorHandlingTest.kt | 85 ++-- .../api/services/ServiceParamsTest.kt | 5 +- .../services/async/SessionServiceAsyncTest.kt | 7 +- .../services/blocking/SessionServiceTest.kt | 7 +- .../api/proguard/ProGuardCompatibilityTest.kt | 1 + 21 files changed, 1424 insertions(+), 226 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5dba58c..d90df61 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-f7d6b6489159f611a2bfdc267ce0a6fc0455bed1ffa0c310044baaa5d8381b9b.yml -openapi_spec_hash: cd88d8068abfde8382da0bed674e440c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-4fb17cafc413ae3d575e3268602b01d2d0e9ebeb734a41b6086b3353ff0d2523.yml +openapi_spec_hash: 8d48d8564849246f6f14d900c6c5f60c config_hash: 5c69fb596588b8ace08203858518c149 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt index e9ae4bc..2ce760b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt @@ -26,6 +26,7 @@ private constructor( private val description: JsonField, private val selector: JsonField, private val arguments: JsonField>, + private val backendNodeId: JsonField, private val method: JsonField, private val additionalProperties: MutableMap, ) { @@ -39,8 +40,11 @@ private constructor( @JsonProperty("arguments") @ExcludeMissing arguments: JsonField> = JsonMissing.of(), + @JsonProperty("backendNodeId") + @ExcludeMissing + backendNodeId: JsonField = JsonMissing.of(), @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), - ) : this(description, selector, arguments, method, mutableMapOf()) + ) : this(description, selector, arguments, backendNodeId, method, mutableMapOf()) /** * Human-readable description of the action @@ -66,6 +70,14 @@ private constructor( */ fun arguments(): Optional> = arguments.getOptional("arguments") + /** + * Backend node ID for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") + /** * The method to execute (click, fill, etc.) * @@ -95,6 +107,15 @@ private constructor( */ @JsonProperty("arguments") @ExcludeMissing fun _arguments(): JsonField> = arguments + /** + * Returns the raw JSON value of [backendNodeId]. + * + * Unlike [backendNodeId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("backendNodeId") + @ExcludeMissing + fun _backendNodeId(): JsonField = backendNodeId + /** * Returns the raw JSON value of [method]. * @@ -134,6 +155,7 @@ private constructor( private var description: JsonField? = null private var selector: JsonField? = null private var arguments: JsonField>? = null + private var backendNodeId: JsonField = JsonMissing.of() private var method: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -142,6 +164,7 @@ private constructor( description = action.description selector = action.selector arguments = action.arguments.map { it.toMutableList() } + backendNodeId = action.backendNodeId method = action.method additionalProperties = action.additionalProperties.toMutableMap() } @@ -195,6 +218,20 @@ private constructor( } } + /** Backend node ID for the element */ + fun backendNodeId(backendNodeId: Double) = backendNodeId(JsonField.of(backendNodeId)) + + /** + * Sets [Builder.backendNodeId] to an arbitrary JSON value. + * + * You should usually call [Builder.backendNodeId] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun backendNodeId(backendNodeId: JsonField) = apply { + this.backendNodeId = backendNodeId + } + /** The method to execute (click, fill, etc.) */ fun method(method: String) = method(JsonField.of(method)) @@ -243,6 +280,7 @@ private constructor( checkRequired("description", description), checkRequired("selector", selector), (arguments ?: JsonMissing.of()).map { it.toImmutable() }, + backendNodeId, method, additionalProperties.toMutableMap(), ) @@ -258,6 +296,7 @@ private constructor( description() selector() arguments() + backendNodeId() method() validated = true } @@ -280,6 +319,7 @@ private constructor( (if (description.asKnown().isPresent) 1 else 0) + (if (selector.asKnown().isPresent) 1 else 0) + (arguments.asKnown().getOrNull()?.size ?: 0) + + (if (backendNodeId.asKnown().isPresent) 1 else 0) + (if (method.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -291,16 +331,17 @@ private constructor( description == other.description && selector == other.selector && arguments == other.arguments && + backendNodeId == other.backendNodeId && method == other.method && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(description, selector, arguments, method, additionalProperties) + Objects.hash(description, selector, arguments, backendNodeId, method, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Action{description=$description, selector=$selector, arguments=$arguments, method=$method, additionalProperties=$additionalProperties}" + "Action{description=$description, selector=$selector, arguments=$arguments, backendNodeId=$backendNodeId, method=$method, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index e416a06..bfbf0aa 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -4,6 +4,7 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.BaseDeserializer import com.browserbase.api.core.BaseSerializer +import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing @@ -26,6 +27,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') @@ -224,6 +226,7 @@ private constructor( private val modelName: JsonField, private val apiKey: JsonField, private val baseUrl: JsonField, + private val provider: JsonField, private val additionalProperties: MutableMap, ) { @@ -234,7 +237,10 @@ private constructor( modelName: JsonField = JsonMissing.of(), @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), - ) : this(modelName, apiKey, baseUrl, mutableMapOf()) + @JsonProperty("provider") + @ExcludeMissing + provider: JsonField = JsonMissing.of(), + ) : this(modelName, apiKey, baseUrl, provider, mutableMapOf()) /** * Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus') @@ -260,6 +266,14 @@ private constructor( */ fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + /** + * AI provider for the model (or provide a baseURL endpoint instead) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun provider(): Optional = provider.getOptional("provider") + /** * Returns the raw JSON value of [modelName]. * @@ -281,6 +295,13 @@ private constructor( */ @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + /** + * Returns the raw JSON value of [provider]. + * + * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -312,6 +333,7 @@ private constructor( private var modelName: JsonField? = null private var apiKey: JsonField = JsonMissing.of() private var baseUrl: JsonField = JsonMissing.of() + private var provider: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -319,6 +341,7 @@ private constructor( modelName = modelConfigObject.modelName apiKey = modelConfigObject.apiKey baseUrl = modelConfigObject.baseUrl + provider = modelConfigObject.provider additionalProperties = modelConfigObject.additionalProperties.toMutableMap() } @@ -358,6 +381,18 @@ private constructor( */ fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + /** AI provider for the model (or provide a baseURL endpoint instead) */ + fun provider(provider: Provider) = provider(JsonField.of(provider)) + + /** + * Sets [Builder.provider] to an arbitrary JSON value. + * + * You should usually call [Builder.provider] with a well-typed [Provider] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun provider(provider: JsonField) = apply { this.provider = provider } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -394,6 +429,7 @@ private constructor( checkRequired("modelName", modelName), apiKey, baseUrl, + provider, additionalProperties.toMutableMap(), ) } @@ -408,6 +444,7 @@ private constructor( modelName() apiKey() baseUrl() + provider().ifPresent { it.validate() } validated = true } @@ -429,7 +466,151 @@ private constructor( internal fun validity(): Int = (if (modelName.asKnown().isPresent) 1 else 0) + (if (apiKey.asKnown().isPresent) 1 else 0) + - (if (baseUrl.asKnown().isPresent) 1 else 0) + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (provider.asKnown().getOrNull()?.validity() ?: 0) + + /** AI provider for the model (or provide a baseURL endpoint instead) */ + class Provider @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPENAI = of("openai") + + @JvmField val ANTHROPIC = of("anthropic") + + @JvmField val GOOGLE = of("google") + + @JvmField val MICROSOFT = of("microsoft") + + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) + } + + /** An enum containing [Provider]'s known values. */ + enum class Known { + OPENAI, + ANTHROPIC, + GOOGLE, + MICROSOFT, + } + + /** + * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Provider] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPENAI, + ANTHROPIC, + GOOGLE, + MICROSOFT, + /** + * An enum member indicating that [Provider] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPENAI -> Value.OPENAI + ANTHROPIC -> Value.ANTHROPIC + GOOGLE -> Value.GOOGLE + MICROSOFT -> Value.MICROSOFT + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + OPENAI -> Known.OPENAI + ANTHROPIC -> Known.ANTHROPIC + GOOGLE -> Known.GOOGLE + MICROSOFT -> Known.MICROSOFT + else -> throw StagehandInvalidDataException("Unknown Provider: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Provider = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Provider && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { @@ -440,16 +621,17 @@ private constructor( modelName == other.modelName && apiKey == other.apiKey && baseUrl == other.baseUrl && + provider == other.provider && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(modelName, apiKey, baseUrl, additionalProperties) + Objects.hash(modelName, apiKey, baseUrl, provider, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "ModelConfigObject{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, additionalProperties=$additionalProperties}" + "ModelConfigObject{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, provider=$provider, additionalProperties=$additionalProperties}" } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt index db27614..62bec51 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -649,6 +649,366 @@ private constructor( (if (message.asKnown().isPresent) 1 else 0) + (if (success.asKnown().isPresent) 1 else 0) + /** Action object returned by observe and used by act */ + class Action + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val selector: JsonField, + private val arguments: JsonField>, + private val backendNodeId: JsonField, + private val method: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField> = JsonMissing.of(), + @JsonProperty("backendNodeId") + @ExcludeMissing + backendNodeId: JsonField = JsonMissing.of(), + @JsonProperty("method") + @ExcludeMissing + method: JsonField = JsonMissing.of(), + ) : this(description, selector, arguments, backendNodeId, method, mutableMapOf()) + + /** + * Human-readable description of the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun description(): String = description.getRequired("description") + + /** + * CSS selector or XPath for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun selector(): String = selector.getRequired("selector") + + /** + * Arguments to pass to the method + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun arguments(): Optional> = arguments.getOptional("arguments") + + /** + * Backend node ID for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") + + /** + * The method to execute (click, fill, etc.) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun method(): Optional = method.getOptional("method") + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("selector") + @ExcludeMissing + fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [arguments]. + * + * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("arguments") + @ExcludeMissing + fun _arguments(): JsonField> = arguments + + /** + * Returns the raw JSON value of [backendNodeId]. + * + * Unlike [backendNodeId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("backendNodeId") + @ExcludeMissing + fun _backendNodeId(): JsonField = backendNodeId + + /** + * Returns the raw JSON value of [method]. + * + * Unlike [method], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Action]. + * + * The following fields are required: + * ```java + * .description() + * .selector() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Action]. */ + class Builder internal constructor() { + + private var description: JsonField? = null + private var selector: JsonField? = null + private var arguments: JsonField>? = null + private var backendNodeId: JsonField = JsonMissing.of() + private var method: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(action: Action) = apply { + description = action.description + selector = action.selector + arguments = action.arguments.map { it.toMutableList() } + backendNodeId = action.backendNodeId + method = action.method + additionalProperties = action.additionalProperties.toMutableMap() + } + + /** Human-readable description of the action */ + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** CSS selector or XPath for the element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** Arguments to pass to the method */ + fun arguments(arguments: List) = arguments(JsonField.of(arguments)) + + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed `List` + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun arguments(arguments: JsonField>) = apply { + this.arguments = arguments.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [arguments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addArgument(argument: String) = apply { + arguments = + (arguments ?: JsonField.of(mutableListOf())).also { + checkKnown("arguments", it).add(argument) + } + } + + /** Backend node ID for the element */ + fun backendNodeId(backendNodeId: Double) = + backendNodeId(JsonField.of(backendNodeId)) + + /** + * Sets [Builder.backendNodeId] to an arbitrary JSON value. + * + * You should usually call [Builder.backendNodeId] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun backendNodeId(backendNodeId: JsonField) = apply { + this.backendNodeId = backendNodeId + } + + /** The method to execute (click, fill, etc.) */ + fun method(method: String) = method(JsonField.of(method)) + + /** + * Sets [Builder.method] to an arbitrary JSON value. + * + * You should usually call [Builder.method] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun method(method: JsonField) = apply { this.method = method } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Action]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .description() + * .selector() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Action = + Action( + checkRequired("description", description), + checkRequired("selector", selector), + (arguments ?: JsonMissing.of()).map { it.toImmutable() }, + backendNodeId, + method, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Action = apply { + if (validated) { + return@apply + } + + description() + selector() + arguments() + backendNodeId() + method() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (description.asKnown().isPresent) 1 else 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (arguments.asKnown().getOrNull()?.size ?: 0) + + (if (backendNodeId.asKnown().isPresent) 1 else 0) + + (if (method.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Action && + description == other.description && + selector == other.selector && + arguments == other.arguments && + backendNodeId == other.backendNodeId && + method == other.method && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + description, + selector, + arguments, + backendNodeId, + method, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Action{description=$description, selector=$selector, arguments=$arguments, backendNodeId=$backendNodeId, method=$method, additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 73880ff..8cb0da8 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -635,6 +635,7 @@ private constructor( private constructor( private val cua: JsonField, private val model: JsonField, + private val provider: JsonField, private val systemPrompt: JsonField, private val additionalProperties: MutableMap, ) { @@ -643,10 +644,13 @@ private constructor( private constructor( @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("provider") + @ExcludeMissing + provider: JsonField = JsonMissing.of(), @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - ) : this(cua, model, systemPrompt, mutableMapOf()) + ) : this(cua, model, provider, systemPrompt, mutableMapOf()) /** * Enable Computer Use Agent mode @@ -665,6 +669,14 @@ private constructor( */ fun model(): Optional = model.getOptional("model") + /** + * AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun provider(): Optional = provider.getOptional("provider") + /** * Custom system prompt for the agent * @@ -687,6 +699,13 @@ private constructor( */ @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + /** + * Returns the raw JSON value of [provider]. + * + * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + /** * Returns the raw JSON value of [systemPrompt]. * @@ -720,6 +739,7 @@ private constructor( private var cua: JsonField = JsonMissing.of() private var model: JsonField = JsonMissing.of() + private var provider: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -727,6 +747,7 @@ private constructor( internal fun from(agentConfig: AgentConfig) = apply { cua = agentConfig.cua model = agentConfig.model + provider = agentConfig.provider systemPrompt = agentConfig.systemPrompt additionalProperties = agentConfig.additionalProperties.toMutableMap() } @@ -767,6 +788,18 @@ private constructor( fun model(modelConfigObject: ModelConfig.ModelConfigObject) = model(ModelConfig.ofModelConfigObject(modelConfigObject)) + /** AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) */ + fun provider(provider: Provider) = provider(JsonField.of(provider)) + + /** + * Sets [Builder.provider] to an arbitrary JSON value. + * + * You should usually call [Builder.provider] with a well-typed [Provider] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun provider(provider: JsonField) = apply { this.provider = provider } + /** Custom system prompt for the agent */ fun systemPrompt(systemPrompt: String) = systemPrompt(JsonField.of(systemPrompt)) @@ -806,7 +839,7 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): AgentConfig = - AgentConfig(cua, model, systemPrompt, additionalProperties.toMutableMap()) + AgentConfig(cua, model, provider, systemPrompt, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -818,6 +851,7 @@ private constructor( cua() model().ifPresent { it.validate() } + provider().ifPresent { it.validate() } systemPrompt() validated = true } @@ -840,8 +874,152 @@ private constructor( internal fun validity(): Int = (if (cua.asKnown().isPresent) 1 else 0) + (model.asKnown().getOrNull()?.validity() ?: 0) + + (provider.asKnown().getOrNull()?.validity() ?: 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + /** AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) */ + class Provider @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPENAI = of("openai") + + @JvmField val ANTHROPIC = of("anthropic") + + @JvmField val GOOGLE = of("google") + + @JvmField val MICROSOFT = of("microsoft") + + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) + } + + /** An enum containing [Provider]'s known values. */ + enum class Known { + OPENAI, + ANTHROPIC, + GOOGLE, + MICROSOFT, + } + + /** + * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Provider] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPENAI, + ANTHROPIC, + GOOGLE, + MICROSOFT, + /** + * An enum member indicating that [Provider] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPENAI -> Value.OPENAI + ANTHROPIC -> Value.ANTHROPIC + GOOGLE -> Value.GOOGLE + MICROSOFT -> Value.MICROSOFT + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + OPENAI -> Known.OPENAI + ANTHROPIC -> Known.ANTHROPIC + GOOGLE -> Known.GOOGLE + MICROSOFT -> Known.MICROSOFT + else -> throw StagehandInvalidDataException("Unknown Provider: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Provider = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Provider && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -850,18 +1028,19 @@ private constructor( return other is AgentConfig && cua == other.cua && model == other.model && + provider == other.provider && systemPrompt == other.systemPrompt && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(cua, model, systemPrompt, additionalProperties) + Objects.hash(cua, model, provider, systemPrompt, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "AgentConfig{cua=$cua, model=$model, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" + "AgentConfig{cua=$cua, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" } class ExecuteOptions diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt index cb2404e..9c1c551 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt @@ -194,7 +194,7 @@ private constructor( class Data @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val result: JsonField>, + private val result: JsonField>, private val actionId: JsonField, private val additionalProperties: MutableMap, ) { @@ -203,7 +203,7 @@ private constructor( private constructor( @JsonProperty("result") @ExcludeMissing - result: JsonField> = JsonMissing.of(), + result: JsonField> = JsonMissing.of(), @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), ) : this(result, actionId, mutableMapOf()) @@ -211,7 +211,7 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun result(): List = result.getRequired("result") + fun result(): List = result.getRequired("result") /** * Action ID for tracking @@ -226,7 +226,7 @@ private constructor( * * Unlike [result], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("result") @ExcludeMissing fun _result(): JsonField> = result + @JsonProperty("result") @ExcludeMissing fun _result(): JsonField> = result /** * Returns the raw JSON value of [actionId]. @@ -263,7 +263,7 @@ private constructor( /** A builder for [Data]. */ class Builder internal constructor() { - private var result: JsonField>? = null + private var result: JsonField>? = null private var actionId: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -274,25 +274,25 @@ private constructor( additionalProperties = data.additionalProperties.toMutableMap() } - fun result(result: List) = result(JsonField.of(result)) + fun result(result: List) = result(JsonField.of(result)) /** * Sets [Builder.result] to an arbitrary JSON value. * - * You should usually call [Builder.result] with a well-typed `List` value + * You should usually call [Builder.result] with a well-typed `List` value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun result(result: JsonField>) = apply { + fun result(result: JsonField>) = apply { this.result = result.map { it.toMutableList() } } /** - * Adds a single [Action] to [Builder.result]. + * Adds a single [Result] to [Builder.result]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addResult(result: Action) = apply { + fun addResult(result: Result) = apply { this.result = (this.result ?: JsonField.of(mutableListOf())).also { checkKnown("result", it).add(result) @@ -381,6 +381,361 @@ private constructor( (result.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (if (actionId.asKnown().isPresent) 1 else 0) + /** Action object returned by observe and used by act */ + class Result + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val selector: JsonField, + private val arguments: JsonField>, + private val backendNodeId: JsonField, + private val method: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("selector") + @ExcludeMissing + selector: JsonField = JsonMissing.of(), + @JsonProperty("arguments") + @ExcludeMissing + arguments: JsonField> = JsonMissing.of(), + @JsonProperty("backendNodeId") + @ExcludeMissing + backendNodeId: JsonField = JsonMissing.of(), + @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), + ) : this(description, selector, arguments, backendNodeId, method, mutableMapOf()) + + /** + * Human-readable description of the action + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun description(): String = description.getRequired("description") + + /** + * CSS selector or XPath for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun selector(): String = selector.getRequired("selector") + + /** + * Arguments to pass to the method + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun arguments(): Optional> = arguments.getOptional("arguments") + + /** + * Backend node ID for the element + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun backendNodeId(): Optional = backendNodeId.getOptional("backendNodeId") + + /** + * The method to execute (click, fill, etc.) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun method(): Optional = method.getOptional("method") + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [selector]. + * + * Unlike [selector], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("selector") @ExcludeMissing fun _selector(): JsonField = selector + + /** + * Returns the raw JSON value of [arguments]. + * + * Unlike [arguments], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("arguments") + @ExcludeMissing + fun _arguments(): JsonField> = arguments + + /** + * Returns the raw JSON value of [backendNodeId]. + * + * Unlike [backendNodeId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("backendNodeId") + @ExcludeMissing + fun _backendNodeId(): JsonField = backendNodeId + + /** + * Returns the raw JSON value of [method]. + * + * Unlike [method], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Result]. + * + * The following fields are required: + * ```java + * .description() + * .selector() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Result]. */ + class Builder internal constructor() { + + private var description: JsonField? = null + private var selector: JsonField? = null + private var arguments: JsonField>? = null + private var backendNodeId: JsonField = JsonMissing.of() + private var method: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(result: Result) = apply { + description = result.description + selector = result.selector + arguments = result.arguments.map { it.toMutableList() } + backendNodeId = result.backendNodeId + method = result.method + additionalProperties = result.additionalProperties.toMutableMap() + } + + /** Human-readable description of the action */ + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + /** CSS selector or XPath for the element */ + fun selector(selector: String) = selector(JsonField.of(selector)) + + /** + * Sets [Builder.selector] to an arbitrary JSON value. + * + * You should usually call [Builder.selector] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun selector(selector: JsonField) = apply { this.selector = selector } + + /** Arguments to pass to the method */ + fun arguments(arguments: List) = arguments(JsonField.of(arguments)) + + /** + * Sets [Builder.arguments] to an arbitrary JSON value. + * + * You should usually call [Builder.arguments] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun arguments(arguments: JsonField>) = apply { + this.arguments = arguments.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [arguments]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addArgument(argument: String) = apply { + arguments = + (arguments ?: JsonField.of(mutableListOf())).also { + checkKnown("arguments", it).add(argument) + } + } + + /** Backend node ID for the element */ + fun backendNodeId(backendNodeId: Double) = + backendNodeId(JsonField.of(backendNodeId)) + + /** + * Sets [Builder.backendNodeId] to an arbitrary JSON value. + * + * You should usually call [Builder.backendNodeId] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun backendNodeId(backendNodeId: JsonField) = apply { + this.backendNodeId = backendNodeId + } + + /** The method to execute (click, fill, etc.) */ + fun method(method: String) = method(JsonField.of(method)) + + /** + * Sets [Builder.method] to an arbitrary JSON value. + * + * You should usually call [Builder.method] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun method(method: JsonField) = apply { this.method = method } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Result]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .description() + * .selector() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Result = + Result( + checkRequired("description", description), + checkRequired("selector", selector), + (arguments ?: JsonMissing.of()).map { it.toImmutable() }, + backendNodeId, + method, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Result = apply { + if (validated) { + return@apply + } + + description() + selector() + arguments() + backendNodeId() + method() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (description.asKnown().isPresent) 1 else 0) + + (if (selector.asKnown().isPresent) 1 else 0) + + (arguments.asKnown().getOrNull()?.size ?: 0) + + (if (backendNodeId.asKnown().isPresent) 1 else 0) + + (if (method.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Result && + description == other.description && + selector == other.selector && + arguments == other.arguments && + backendNodeId == other.backendNodeId && + method == other.method && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + description, + selector, + arguments, + backendNodeId, + method, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Result{description=$description, selector=$selector, arguments=$arguments, backendNodeId=$backendNodeId, method=$method, additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 16eecb4..ca9fdd1 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -72,7 +72,7 @@ private constructor( fun modelName(): String = body.modelName() /** - * Timeout in ms for act operations + * Timeout in ms for act operations (deprecated, v2 only) * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -100,12 +100,6 @@ private constructor( */ fun browserbaseSessionId(): Optional = body.browserbaseSessionId() - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun debugDom(): Optional = body.debugDom() - /** * Timeout in ms to wait for DOM to settle * @@ -142,9 +136,11 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun verbose(): Optional = body.verbose() + fun verbose(): Optional = body.verbose() /** + * Wait for captcha solves (deprecated, v2 only) + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ @@ -188,13 +184,6 @@ private constructor( */ fun _browserbaseSessionId(): JsonField = body._browserbaseSessionId() - /** - * Returns the raw JSON value of [debugDom]. - * - * Unlike [debugDom], this method doesn't throw if the JSON field has an unexpected type. - */ - fun _debugDom(): JsonField = body._debugDom() - /** * Returns the raw JSON value of [domSettleTimeoutMs]. * @@ -229,7 +218,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - fun _verbose(): JsonField = body._verbose() + fun _verbose(): JsonField = body._verbose() /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -337,7 +326,7 @@ private constructor( */ fun modelName(modelName: JsonField) = apply { body.modelName(modelName) } - /** Timeout in ms for act operations */ + /** Timeout in ms for act operations (deprecated, v2 only) */ fun actTimeoutMs(actTimeoutMs: Double) = apply { body.actTimeoutMs(actTimeoutMs) } /** @@ -392,17 +381,6 @@ private constructor( body.browserbaseSessionId(browserbaseSessionId) } - fun debugDom(debugDom: Boolean) = apply { body.debugDom(debugDom) } - - /** - * Sets [Builder.debugDom] to an arbitrary JSON value. - * - * You should usually call [Builder.debugDom] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun debugDom(debugDom: JsonField) = apply { body.debugDom(debugDom) } - /** Timeout in ms to wait for DOM to settle */ fun domSettleTimeoutMs(domSettleTimeoutMs: Double) = apply { body.domSettleTimeoutMs(domSettleTimeoutMs) @@ -459,16 +437,17 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Long) = apply { body.verbose(verbose) } + fun verbose(verbose: Verbose) = apply { body.verbose(verbose) } /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Long] value instead. This + * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + fun verbose(verbose: JsonField) = apply { body.verbose(verbose) } + /** Wait for captcha solves (deprecated, v2 only) */ fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = apply { body.waitForCaptchaSolves(waitForCaptchaSolves) } @@ -648,12 +627,11 @@ private constructor( private val browser: JsonField, private val browserbaseSessionCreateParams: JsonField, private val browserbaseSessionId: JsonField, - private val debugDom: JsonField, private val domSettleTimeoutMs: JsonField, private val experimental: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, - private val verbose: JsonField, + private val verbose: JsonField, private val waitForCaptchaSolves: JsonField, private val additionalProperties: MutableMap, ) { @@ -674,9 +652,6 @@ private constructor( @JsonProperty("browserbaseSessionID") @ExcludeMissing browserbaseSessionId: JsonField = JsonMissing.of(), - @JsonProperty("debugDom") - @ExcludeMissing - debugDom: JsonField = JsonMissing.of(), @JsonProperty("domSettleTimeoutMs") @ExcludeMissing domSettleTimeoutMs: JsonField = JsonMissing.of(), @@ -689,7 +664,7 @@ private constructor( @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), + @JsonProperty("verbose") @ExcludeMissing verbose: JsonField = JsonMissing.of(), @JsonProperty("waitForCaptchaSolves") @ExcludeMissing waitForCaptchaSolves: JsonField = JsonMissing.of(), @@ -699,7 +674,6 @@ private constructor( browser, browserbaseSessionCreateParams, browserbaseSessionId, - debugDom, domSettleTimeoutMs, experimental, selfHeal, @@ -718,7 +692,7 @@ private constructor( fun modelName(): String = modelName.getRequired("modelName") /** - * Timeout in ms for act operations + * Timeout in ms for act operations (deprecated, v2 only) * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -747,12 +721,6 @@ private constructor( fun browserbaseSessionId(): Optional = browserbaseSessionId.getOptional("browserbaseSessionID") - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun debugDom(): Optional = debugDom.getOptional("debugDom") - /** * Timeout in ms to wait for DOM to settle * @@ -790,9 +758,11 @@ private constructor( * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verbose(): Optional = verbose.getOptional("verbose") + fun verbose(): Optional = verbose.getOptional("verbose") /** + * Wait for captcha solves (deprecated, v2 only) + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -844,13 +814,6 @@ private constructor( @ExcludeMissing fun _browserbaseSessionId(): JsonField = browserbaseSessionId - /** - * Returns the raw JSON value of [debugDom]. - * - * Unlike [debugDom], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("debugDom") @ExcludeMissing fun _debugDom(): JsonField = debugDom - /** * Returns the raw JSON value of [domSettleTimeoutMs]. * @@ -893,7 +856,7 @@ private constructor( * * Unlike [verbose], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose + @JsonProperty("verbose") @ExcludeMissing fun _verbose(): JsonField = verbose /** * Returns the raw JSON value of [waitForCaptchaSolves]. @@ -939,12 +902,11 @@ private constructor( private var browserbaseSessionCreateParams: JsonField = JsonMissing.of() private var browserbaseSessionId: JsonField = JsonMissing.of() - private var debugDom: JsonField = JsonMissing.of() private var domSettleTimeoutMs: JsonField = JsonMissing.of() private var experimental: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() - private var verbose: JsonField = JsonMissing.of() + private var verbose: JsonField = JsonMissing.of() private var waitForCaptchaSolves: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -955,7 +917,6 @@ private constructor( browser = body.browser browserbaseSessionCreateParams = body.browserbaseSessionCreateParams browserbaseSessionId = body.browserbaseSessionId - debugDom = body.debugDom domSettleTimeoutMs = body.domSettleTimeoutMs experimental = body.experimental selfHeal = body.selfHeal @@ -977,7 +938,7 @@ private constructor( */ fun modelName(modelName: JsonField) = apply { this.modelName = modelName } - /** Timeout in ms for act operations */ + /** Timeout in ms for act operations (deprecated, v2 only) */ fun actTimeoutMs(actTimeoutMs: Double) = actTimeoutMs(JsonField.of(actTimeoutMs)) /** @@ -1032,17 +993,6 @@ private constructor( this.browserbaseSessionId = browserbaseSessionId } - fun debugDom(debugDom: Boolean) = debugDom(JsonField.of(debugDom)) - - /** - * Sets [Builder.debugDom] to an arbitrary JSON value. - * - * You should usually call [Builder.debugDom] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun debugDom(debugDom: JsonField) = apply { this.debugDom = debugDom } - /** Timeout in ms to wait for DOM to settle */ fun domSettleTimeoutMs(domSettleTimeoutMs: Double) = domSettleTimeoutMs(JsonField.of(domSettleTimeoutMs)) @@ -1098,17 +1048,18 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - fun verbose(verbose: Long) = verbose(JsonField.of(verbose)) + fun verbose(verbose: Verbose) = verbose(JsonField.of(verbose)) /** * Sets [Builder.verbose] to an arbitrary JSON value. * - * You should usually call [Builder.verbose] with a well-typed [Long] value instead. + * You should usually call [Builder.verbose] with a well-typed [Verbose] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + fun verbose(verbose: JsonField) = apply { this.verbose = verbose } + /** Wait for captcha solves (deprecated, v2 only) */ fun waitForCaptchaSolves(waitForCaptchaSolves: Boolean) = waitForCaptchaSolves(JsonField.of(waitForCaptchaSolves)) @@ -1161,7 +1112,6 @@ private constructor( browser, browserbaseSessionCreateParams, browserbaseSessionId, - debugDom, domSettleTimeoutMs, experimental, selfHeal, @@ -1184,12 +1134,11 @@ private constructor( browser().ifPresent { it.validate() } browserbaseSessionCreateParams().ifPresent { it.validate() } browserbaseSessionId() - debugDom() domSettleTimeoutMs() experimental() selfHeal() systemPrompt() - verbose() + verbose().ifPresent { it.validate() } waitForCaptchaSolves() validated = true } @@ -1215,12 +1164,11 @@ private constructor( (browser.asKnown().getOrNull()?.validity() ?: 0) + (browserbaseSessionCreateParams.asKnown().getOrNull()?.validity() ?: 0) + (if (browserbaseSessionId.asKnown().isPresent) 1 else 0) + - (if (debugDom.asKnown().isPresent) 1 else 0) + (if (domSettleTimeoutMs.asKnown().isPresent) 1 else 0) + (if (experimental.asKnown().isPresent) 1 else 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + - (if (verbose.asKnown().isPresent) 1 else 0) + + (verbose.asKnown().getOrNull()?.validity() ?: 0) + (if (waitForCaptchaSolves.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -1234,7 +1182,6 @@ private constructor( browser == other.browser && browserbaseSessionCreateParams == other.browserbaseSessionCreateParams && browserbaseSessionId == other.browserbaseSessionId && - debugDom == other.debugDom && domSettleTimeoutMs == other.domSettleTimeoutMs && experimental == other.experimental && selfHeal == other.selfHeal && @@ -1251,7 +1198,6 @@ private constructor( browser, browserbaseSessionCreateParams, browserbaseSessionId, - debugDom, domSettleTimeoutMs, experimental, selfHeal, @@ -1265,7 +1211,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, debugDom=$debugDom, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" + "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" } class Browser @@ -7114,6 +7060,140 @@ private constructor( "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" } + /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ + class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val _0 = of("0") + + @JvmField val _1 = of("1") + + @JvmField val _2 = of("2") + + @JvmStatic fun of(value: String) = Verbose(JsonField.of(value)) + } + + /** An enum containing [Verbose]'s known values. */ + enum class Known { + _0, + _1, + _2, + } + + /** + * An enum containing [Verbose]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Verbose] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + _0, + _1, + _2, + /** An enum member indicating that [Verbose] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + _0 -> Value._0 + _1 -> Value._1 + _2 -> Value._2 + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + _0 -> Known._0 + _1 -> Known._1 + _2 -> Known._2 + else -> throw StagehandInvalidDataException("Unknown Verbose: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Verbose = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Verbose && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + /** Client SDK language */ class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index 13ed630..e342e19 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -14,6 +14,7 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty import java.util.Collections import java.util.Objects +import java.util.Optional import kotlin.jvm.optionals.getOrNull class SessionStartResponse @@ -192,8 +193,8 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val available: JsonField, - private val connectUrl: JsonField, private val sessionId: JsonField, + private val cdpUrl: JsonField, private val additionalProperties: MutableMap, ) { @@ -202,13 +203,11 @@ private constructor( @JsonProperty("available") @ExcludeMissing available: JsonField = JsonMissing.of(), - @JsonProperty("connectUrl") - @ExcludeMissing - connectUrl: JsonField = JsonMissing.of(), @JsonProperty("sessionId") @ExcludeMissing sessionId: JsonField = JsonMissing.of(), - ) : this(available, connectUrl, sessionId, mutableMapOf()) + @JsonProperty("cdpUrl") @ExcludeMissing cdpUrl: JsonField = JsonMissing.of(), + ) : this(available, sessionId, cdpUrl, mutableMapOf()) /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is @@ -217,20 +216,21 @@ private constructor( fun available(): Boolean = available.getRequired("available") /** - * CDP WebSocket URL for connecting to the Browserbase cloud browser + * Unique Browserbase session identifier * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun connectUrl(): String = connectUrl.getRequired("connectUrl") + fun sessionId(): String = sessionId.getRequired("sessionId") /** - * Unique Browserbase session identifier + * CDP WebSocket URL for connecting to the Browserbase cloud browser (present when + * available) * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). */ - fun sessionId(): String = sessionId.getRequired("sessionId") + fun cdpUrl(): Optional = cdpUrl.getOptional("cdpUrl") /** * Returns the raw JSON value of [available]. @@ -240,20 +240,18 @@ private constructor( @JsonProperty("available") @ExcludeMissing fun _available(): JsonField = available /** - * Returns the raw JSON value of [connectUrl]. + * Returns the raw JSON value of [sessionId]. * - * Unlike [connectUrl], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [sessionId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("connectUrl") - @ExcludeMissing - fun _connectUrl(): JsonField = connectUrl + @JsonProperty("sessionId") @ExcludeMissing fun _sessionId(): JsonField = sessionId /** - * Returns the raw JSON value of [sessionId]. + * Returns the raw JSON value of [cdpUrl]. * - * Unlike [sessionId], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [cdpUrl], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("sessionId") @ExcludeMissing fun _sessionId(): JsonField = sessionId + @JsonProperty("cdpUrl") @ExcludeMissing fun _cdpUrl(): JsonField = cdpUrl @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -275,7 +273,6 @@ private constructor( * The following fields are required: * ```java * .available() - * .connectUrl() * .sessionId() * ``` */ @@ -286,15 +283,15 @@ private constructor( class Builder internal constructor() { private var available: JsonField? = null - private var connectUrl: JsonField? = null private var sessionId: JsonField? = null + private var cdpUrl: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(data: Data) = apply { available = data.available - connectUrl = data.connectUrl sessionId = data.sessionId + cdpUrl = data.cdpUrl additionalProperties = data.additionalProperties.toMutableMap() } @@ -309,29 +306,35 @@ private constructor( */ fun available(available: JsonField) = apply { this.available = available } - /** CDP WebSocket URL for connecting to the Browserbase cloud browser */ - fun connectUrl(connectUrl: String) = connectUrl(JsonField.of(connectUrl)) + /** Unique Browserbase session identifier */ + fun sessionId(sessionId: String) = sessionId(JsonField.of(sessionId)) /** - * Sets [Builder.connectUrl] to an arbitrary JSON value. + * Sets [Builder.sessionId] to an arbitrary JSON value. * - * You should usually call [Builder.connectUrl] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.sessionId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun connectUrl(connectUrl: JsonField) = apply { this.connectUrl = connectUrl } + fun sessionId(sessionId: JsonField) = apply { this.sessionId = sessionId } - /** Unique Browserbase session identifier */ - fun sessionId(sessionId: String) = sessionId(JsonField.of(sessionId)) + /** + * CDP WebSocket URL for connecting to the Browserbase cloud browser (present when + * available) + */ + fun cdpUrl(cdpUrl: String?) = cdpUrl(JsonField.ofNullable(cdpUrl)) + + /** Alias for calling [Builder.cdpUrl] with `cdpUrl.orElse(null)`. */ + fun cdpUrl(cdpUrl: Optional) = cdpUrl(cdpUrl.getOrNull()) /** - * Sets [Builder.sessionId] to an arbitrary JSON value. + * Sets [Builder.cdpUrl] to an arbitrary JSON value. * - * You should usually call [Builder.sessionId] with a well-typed [String] value instead. + * You should usually call [Builder.cdpUrl] with a well-typed [String] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun sessionId(sessionId: JsonField) = apply { this.sessionId = sessionId } + fun cdpUrl(cdpUrl: JsonField) = apply { this.cdpUrl = cdpUrl } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -360,7 +363,6 @@ private constructor( * The following fields are required: * ```java * .available() - * .connectUrl() * .sessionId() * ``` * @@ -369,8 +371,8 @@ private constructor( fun build(): Data = Data( checkRequired("available", available), - checkRequired("connectUrl", connectUrl), checkRequired("sessionId", sessionId), + cdpUrl, additionalProperties.toMutableMap(), ) } @@ -383,8 +385,8 @@ private constructor( } available() - connectUrl() sessionId() + cdpUrl() validated = true } @@ -405,8 +407,8 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (available.asKnown().isPresent) 1 else 0) + - (if (connectUrl.asKnown().isPresent) 1 else 0) + - (if (sessionId.asKnown().isPresent) 1 else 0) + (if (sessionId.asKnown().isPresent) 1 else 0) + + (if (cdpUrl.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -415,19 +417,19 @@ private constructor( return other is Data && available == other.available && - connectUrl == other.connectUrl && sessionId == other.sessionId && + cdpUrl == other.cdpUrl && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(available, connectUrl, sessionId, additionalProperties) + Objects.hash(available, sessionId, cdpUrl, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Data{available=$available, connectUrl=$connectUrl, sessionId=$sessionId, additionalProperties=$additionalProperties}" + "Data{available=$available, sessionId=$sessionId, cdpUrl=$cdpUrl, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt index d58dc3b..a123e6a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -29,7 +29,10 @@ import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -/** Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. */ +/** + * Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. Key + * order: data (with status first), type, id. + */ class StreamEvent @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt index 4464f91..c76617d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ActionTest.kt @@ -17,12 +17,14 @@ internal class ActionTest { .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() assertThat(action.description()).isEqualTo("Click the submit button") assertThat(action.selector()).isEqualTo("[data-testid='submit-button']") assertThat(action.arguments().getOrNull()).containsExactly("Hello World") + assertThat(action.backendNodeId()).contains(0.0) assertThat(action.method()).contains("click") } @@ -34,6 +36,7 @@ internal class ActionTest { .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index d83a01a..fc5ea48 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -43,6 +43,7 @@ internal class ModelConfigTest { .modelName("gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) .build() val modelConfig = ModelConfig.ofModelConfigObject(modelConfigObject) @@ -60,6 +61,7 @@ internal class ModelConfigTest { .modelName("gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt index f5e0363..52cc63c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActResponseTest.kt @@ -19,10 +19,11 @@ internal class SessionActResponseTest { SessionActResponse.Data.Result.builder() .actionDescription("Clicked button with text 'Login'") .addAction( - Action.builder() + SessionActResponse.Data.Result.Action.builder() .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() ) @@ -43,10 +44,11 @@ internal class SessionActResponseTest { SessionActResponse.Data.Result.builder() .actionDescription("Clicked button with text 'Login'") .addAction( - Action.builder() + SessionActResponse.Data.Result.Action.builder() .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() ) @@ -71,10 +73,11 @@ internal class SessionActResponseTest { SessionActResponse.Data.Result.builder() .actionDescription("Clicked button with text 'Login'") .addAction( - Action.builder() + SessionActResponse.Data.Result.Action.builder() .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 4de6985..8869791 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -21,6 +21,7 @@ internal class SessionExecuteParamsTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -70,6 +71,7 @@ internal class SessionExecuteParamsTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -131,6 +133,7 @@ internal class SessionExecuteParamsTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -153,6 +156,7 @@ internal class SessionExecuteParamsTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt index 2cc31b8..938fff3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveResponseTest.kt @@ -16,10 +16,11 @@ internal class SessionObserveResponseTest { .data( SessionObserveResponse.Data.builder() .addResult( - Action.builder() + SessionObserveResponse.Data.Result.builder() .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() ) @@ -33,10 +34,11 @@ internal class SessionObserveResponseTest { .isEqualTo( SessionObserveResponse.Data.builder() .addResult( - Action.builder() + SessionObserveResponse.Data.Result.builder() .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() ) @@ -54,10 +56,11 @@ internal class SessionObserveResponseTest { .data( SessionObserveResponse.Data.builder() .addResult( - Action.builder() + SessionObserveResponse.Data.Result.builder() .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 56f4736..765a962 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -18,7 +18,7 @@ internal class SessionStartParamsTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -148,12 +148,11 @@ internal class SessionStartParamsTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() } @@ -167,7 +166,7 @@ internal class SessionStartParamsTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -301,12 +300,11 @@ internal class SessionStartParamsTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() @@ -341,7 +339,7 @@ internal class SessionStartParamsTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -475,19 +473,18 @@ internal class SessionStartParamsTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() val body = params._body() assertThat(body.modelName()).isEqualTo("gpt-4o") - assertThat(body.actTimeoutMs()).contains(30000.0) + assertThat(body.actTimeoutMs()).contains(0.0) assertThat(body.browser()) .contains( SessionStartParams.Browser.builder() @@ -619,12 +616,11 @@ internal class SessionStartParamsTest { .build() ) assertThat(body.browserbaseSessionId()).contains("browserbaseSessionID") - assertThat(body.debugDom()).contains(true) assertThat(body.domSettleTimeoutMs()).contains(5000.0) assertThat(body.experimental()).contains(true) assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") - assertThat(body.verbose()).contains(1L) + assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) assertThat(body.waitForCaptchaSolves()).contains(true) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt index 4a712ec..0ae6883 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartResponseTest.kt @@ -16,8 +16,8 @@ internal class SessionStartResponseTest { .data( SessionStartResponse.Data.builder() .available(true) - .connectUrl("wss://connect.browserbase.com/?signingKey=abc123") .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .cdpUrl("wss://connect.browserbase.com/?signingKey=abc123") .build() ) .success(true) @@ -27,8 +27,8 @@ internal class SessionStartResponseTest { .isEqualTo( SessionStartResponse.Data.builder() .available(true) - .connectUrl("wss://connect.browserbase.com/?signingKey=abc123") .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .cdpUrl("wss://connect.browserbase.com/?signingKey=abc123") .build() ) assertThat(sessionStartResponse.success()).isEqualTo(true) @@ -42,8 +42,8 @@ internal class SessionStartResponseTest { .data( SessionStartResponse.Data.builder() .available(true) - .connectUrl("wss://connect.browserbase.com/?signingKey=abc123") .sessionId("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .cdpUrl("wss://connect.browserbase.com/?signingKey=abc123") .build() ) .success(true) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index e453d81..f704c1a 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -80,7 +80,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -225,12 +225,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -260,7 +259,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -405,12 +404,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -440,7 +438,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -585,12 +583,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -620,7 +617,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -765,12 +762,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -800,7 +796,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -945,12 +941,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -980,7 +975,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -1125,12 +1120,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1160,7 +1154,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -1305,12 +1299,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1340,7 +1333,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -1485,12 +1478,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1520,7 +1512,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -1665,12 +1657,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1700,7 +1691,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -1845,12 +1836,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -1880,7 +1870,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -2025,12 +2015,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2060,7 +2049,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -2205,12 +2194,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2240,7 +2228,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -2385,12 +2373,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2420,7 +2407,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -2565,12 +2552,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2600,7 +2586,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -2745,12 +2731,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2780,7 +2765,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -2925,12 +2910,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) @@ -2958,7 +2942,7 @@ internal class ErrorHandlingTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -3103,12 +3087,11 @@ internal class ErrorHandlingTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 0cdc99d..2243046 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -53,7 +53,7 @@ internal class ServiceParamsTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -187,12 +187,11 @@ internal class ServiceParamsTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 78ba6e7..f9bc4be 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -152,6 +152,7 @@ internal class SessionServiceAsyncTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -196,6 +197,7 @@ internal class SessionServiceAsyncTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -430,7 +432,7 @@ internal class SessionServiceAsyncTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -567,12 +569,11 @@ internal class SessionServiceAsyncTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 3355c14..1bad240 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -150,6 +150,7 @@ internal class SessionServiceTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -193,6 +194,7 @@ internal class SessionServiceTest { SessionExecuteParams.AgentConfig.builder() .cua(true) .model("openai/gpt-5-nano") + .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() ) @@ -424,7 +426,7 @@ internal class SessionServiceTest { .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") - .actTimeoutMs(30000.0) + .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() .cdpUrl("ws://localhost:9222") @@ -561,12 +563,11 @@ internal class SessionServiceTest { .build() ) .browserbaseSessionId("browserbaseSessionID") - .debugDom(true) .domSettleTimeoutMs(5000.0) .experimental(true) .selfHeal(true) .systemPrompt("systemPrompt") - .verbose(1L) + .verbose(SessionStartParams.Verbose._1) .waitForCaptchaSolves(true) .build() ) diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 0d52560..f3e08fa 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -64,6 +64,7 @@ internal class ProGuardCompatibilityTest { .description("Click the submit button") .selector("[data-testid='submit-button']") .addArgument("Hello World") + .backendNodeId(0.0) .method("click") .build() From fabb2a8f17b14386a49fcd1a8ba4364362a47c7e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 20 Dec 2025 04:57:19 +0000 Subject: [PATCH 039/164] docs: add more examples --- README.md | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/README.md b/README.md index be1932d..251bfd6 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,98 @@ CompletableFuture response = client.sessions().act(params); The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. +## Streaming + +The SDK defines methods that return response "chunk" streams, where each chunk can be individually processed as soon as it arrives instead of waiting on the full response. Streaming methods generally correspond to [SSE](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) or [JSONL](https://jsonlines.org) responses. + +Some of these methods may have streaming and non-streaming variants, but a streaming method will always have a `Streaming` suffix in its name, even if it doesn't have a non-streaming variant. + +These streaming methods return [`StreamResponse`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/StreamResponse.kt) for synchronous clients: + +```java +import com.browserbase.api.core.http.StreamResponse; +import com.browserbase.api.models.sessions.StreamEvent; + +try (StreamResponse streamResponse = client.sessions().actStreaming(params)) { + streamResponse.stream().forEach(chunk -> { + System.out.println(chunk); + }); + System.out.println("No more chunks!"); +} +``` + +Or [`AsyncStreamResponse`](stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/AsyncStreamResponse.kt) for asynchronous clients: + +```java +import com.browserbase.api.core.http.AsyncStreamResponse; +import com.browserbase.api.models.sessions.StreamEvent; +import java.util.Optional; + +client.async().sessions().actStreaming(params).subscribe(chunk -> { + System.out.println(chunk); +}); + +// If you need to handle errors or completion of the stream +client.async().sessions().actStreaming(params).subscribe(new AsyncStreamResponse.Handler<>() { + @Override + public void onNext(StreamEvent chunk) { + System.out.println(chunk); + } + + @Override + public void onComplete(Optional error) { + if (error.isPresent()) { + System.out.println("Something went wrong!"); + throw new RuntimeException(error.get()); + } else { + System.out.println("No more chunks!"); + } + } +}); + +// Or use futures +client.async().sessions().actStreaming(params) + .subscribe(chunk -> { + System.out.println(chunk); + }) + .onCompleteFuture(); + .whenComplete((unused, error) -> { + if (error != null) { + System.out.println("Something went wrong!"); + throw new RuntimeException(error); + } else { + System.out.println("No more chunks!"); + } + }); +``` + +Async streaming uses a dedicated per-client cached thread pool [`Executor`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html) to stream without blocking the current thread. This default is suitable for most purposes. + +To use a different `Executor`, configure the subscription using the `executor` parameter: + +```java +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +Executor executor = Executors.newFixedThreadPool(4); +client.async().sessions().actStreaming(params).subscribe( + chunk -> System.out.println(chunk), executor +); +``` + +Or configure the client globally using the `streamHandlerExecutor` method: + +```java +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; +import java.util.concurrent.Executors; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .streamHandlerExecutor(Executors.newFixedThreadPool(4)) + .build(); +``` + ## Raw responses The SDK defines methods that deserialize responses into instances of Java classes. However, these methods don't provide access to the response headers, status code, or the raw response body. From 33e30494217eba9230ff4dbdd93af33eff1079e7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 21:50:02 +0000 Subject: [PATCH 040/164] feat: [STG-1053] [server] Use fastify-zod-openapi + zod v4 for openapi generation --- .stats.yml | 4 ++-- .../api/models/sessions/SessionStartParams.kt | 22 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index d90df61..2c7a523 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-4fb17cafc413ae3d575e3268602b01d2d0e9ebeb734a41b6086b3353ff0d2523.yml -openapi_spec_hash: 8d48d8564849246f6f14d900c6c5f60c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml +openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23 config_hash: 5c69fb596588b8ace08203858518c149 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index ca9fdd1..3a7009b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -7061,7 +7061,7 @@ private constructor( } /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ - class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { + class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { /** * Returns this class instance's raw value. @@ -7071,17 +7071,17 @@ private constructor( * older version than the API, then the API may respond with new members that the SDK is * unaware of. */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value companion object { - @JvmField val _0 = of("0") + @JvmField val _0 = of(0.0) - @JvmField val _1 = of("1") + @JvmField val _1 = of(1.0) - @JvmField val _2 = of("2") + @JvmField val _2 = of(2.0) - @JvmStatic fun of(value: String) = Verbose(JsonField.of(value)) + @JvmStatic fun of(value: Double) = Verbose(JsonField.of(value)) } /** An enum containing [Verbose]'s known values. */ @@ -7143,16 +7143,12 @@ private constructor( /** * Returns this class instance's primitive wire representation. * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * * @throws StagehandInvalidDataException if this class instance's value does not have the * expected primitive type. */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } + fun asDouble(): Double = + _value().asNumber().getOrNull()?.toDouble() + ?: throw StagehandInvalidDataException("Value is not a Double") private var validated: Boolean = false From d192d1d8f4f88274ea2715d5a1eca15dd6d9bb06 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:53:39 +0000 Subject: [PATCH 041/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2c7a523..21604fb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23 -config_hash: 5c69fb596588b8ace08203858518c149 +config_hash: 6b5d2b7e13aea77b1fd038e5eb8c0662 From 9f11f4f1bb0382b848d65a094182010aa21b5a07 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:07:15 +0000 Subject: [PATCH 042/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 21604fb..5a89fb7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23 -config_hash: 6b5d2b7e13aea77b1fd038e5eb8c0662 +config_hash: 989ddfee371586e9156b4d484ec0a6cc From 121cde04b454a4fb6fc807a711a5dd493197d8e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:31:47 +0000 Subject: [PATCH 043/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- LICENSE | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 10f3091..6b7b74c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.2.0" + ".": "0.3.0" } \ No newline at end of file diff --git a/LICENSE b/LICENSE index 6b24314..d15d021 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Stagehand + Copyright 2026 Stagehand Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 251bfd6..ab416ca 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.2.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.2.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.2.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.3.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.3.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.3.0) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.2.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.3.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.2.0") +implementation("com.browserbase.api:stagehand-java:0.3.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.browserbase.api:stagehand-java:0.2.0") com.browserbase.api stagehand-java - 0.2.0 + 0.3.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 63a11b4..d06f0a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.2.0" // x-release-please-version + version = "0.3.0" // x-release-please-version } subprojects { From 388dc5075a9ba0aaaca613701363b26c730491de Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:37:56 +0000 Subject: [PATCH 044/164] feat(api): manual updates --- .stats.yml | 2 +- README.md | 12 ++++++------ .../api/client/okhttp/StagehandOkHttpClient.kt | 2 +- .../okhttp/StagehandOkHttpClientAsync.kt | 2 +- .../com/browserbase/api/core/ClientOptions.kt | 18 +++++++++--------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5a89fb7..3a11178 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23 -config_hash: 989ddfee371586e9156b4d484ec0a6cc +config_hash: 8ec9eaf59304f664cf79f73de1488671 diff --git a/README.md b/README.md index ab416ca..516d9e6 100644 --- a/README.md +++ b/README.md @@ -104,12 +104,12 @@ StagehandClient client = StagehandOkHttpClient.builder() See this table for the available options: -| Setter | System property | Environment variable | Required | Default value | -| ---------------------- | -------------------------------- | ------------------------ | -------- | -------------------------------------------- | -| `browserbaseApiKey` | `stagehand.browserbaseApiKey` | `BROWSERBASE_API_KEY` | true | - | -| `browserbaseProjectId` | `stagehand.browserbaseProjectId` | `BROWSERBASE_PROJECT_ID` | true | - | -| `modelApiKey` | `stagehand.modelApiKey` | `MODEL_API_KEY` | true | - | -| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com/v1"` | +| Setter | System property | Environment variable | Required | Default value | +| ---------------------- | -------------------------------- | ------------------------ | -------- | ----------------------------------------- | +| `browserbaseApiKey` | `stagehand.browserbaseApiKey` | `BROWSERBASE_API_KEY` | true | - | +| `browserbaseProjectId` | `stagehand.browserbaseProjectId` | `BROWSERBASE_PROJECT_ID` | true | - | +| `modelApiKey` | `stagehand.modelApiKey` | `MODEL_API_KEY` | true | - | +| `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com"` | System properties take precedence over environment variables. diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index 40010ee..0588b0d 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -157,7 +157,7 @@ class StagehandOkHttpClient private constructor() { /** * The base URL to use for every request. * - * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com`. */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 33ce68f..7f2ea56 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -157,7 +157,7 @@ class StagehandOkHttpClientAsync private constructor() { /** * The base URL to use for every request. * - * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com`. */ fun baseUrl(baseUrl: String?) = apply { clientOptions.baseUrl(baseUrl) } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 2da3f9a..732c468 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -124,7 +124,7 @@ private constructor( /** * The base URL to use for every request. * - * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com`. */ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL @@ -132,7 +132,7 @@ private constructor( companion object { - const val PRODUCTION_URL = "https://api.stagehand.browserbase.com/v1" + const val PRODUCTION_URL = "https://api.stagehand.browserbase.com" /** * Returns a mutable builder for constructing an instance of [ClientOptions]. @@ -260,7 +260,7 @@ private constructor( /** * The base URL to use for every request. * - * Defaults to the production environment: `https://api.stagehand.browserbase.com/v1`. + * Defaults to the production environment: `https://api.stagehand.browserbase.com`. */ fun baseUrl(baseUrl: String?) = apply { this.baseUrl = baseUrl } @@ -411,12 +411,12 @@ private constructor( * * See this table for the available options: * - * |Setter |System property |Environment variable |Required|Default value | - * |----------------------|--------------------------------|------------------------|--------|--------------------------------------------| - * |`browserbaseApiKey` |`stagehand.browserbaseApiKey` |`BROWSERBASE_API_KEY` |true |- | - * |`browserbaseProjectId`|`stagehand.browserbaseProjectId`|`BROWSERBASE_PROJECT_ID`|true |- | - * |`modelApiKey` |`stagehand.modelApiKey` |`MODEL_API_KEY` |true |- | - * |`baseUrl` |`stagehand.baseUrl` |`STAGEHAND_BASE_URL` |true |`"https://api.stagehand.browserbase.com/v1"`| + * |Setter |System property |Environment variable |Required|Default value | + * |----------------------|--------------------------------|------------------------|--------|-----------------------------------------| + * |`browserbaseApiKey` |`stagehand.browserbaseApiKey` |`BROWSERBASE_API_KEY` |true |- | + * |`browserbaseProjectId`|`stagehand.browserbaseProjectId`|`BROWSERBASE_PROJECT_ID`|true |- | + * |`modelApiKey` |`stagehand.modelApiKey` |`MODEL_API_KEY` |true |- | + * |`baseUrl` |`stagehand.baseUrl` |`STAGEHAND_BASE_URL` |true |`"https://api.stagehand.browserbase.com"`| * * System properties take precedence over environment variables. */ From a30a9d4016ecbcf887f4e20e0ec42749688ee3df Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 00:13:13 +0000 Subject: [PATCH 045/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6b7b74c..da59f99 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.3.0" + ".": "0.4.0" } \ No newline at end of file diff --git a/README.md b/README.md index 516d9e6..abb13e3 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.3.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.3.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.3.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.4.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.4.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.4.0) @@ -13,7 +13,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.3.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.4.0). @@ -24,7 +24,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.3.0") +implementation("com.browserbase.api:stagehand-java:0.4.0") ``` ### Maven @@ -33,7 +33,7 @@ implementation("com.browserbase.api:stagehand-java:0.3.0") com.browserbase.api stagehand-java - 0.3.0 + 0.4.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index d06f0a9..bd9f794 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.3.0" // x-release-please-version + version = "0.4.0" // x-release-please-version } subprojects { From d0837922e56593fecff0198261cc56eecaae875e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 03:46:00 +0000 Subject: [PATCH 046/164] feat: /end endpoint returns empty object --- .stats.yml | 6 +- .../api/models/sessions/SessionEndParams.kt | 66 ++++++++----------- .../api/services/async/SessionServiceAsync.kt | 44 ++++--------- .../services/async/SessionServiceAsyncImpl.kt | 2 +- .../api/services/blocking/SessionService.kt | 36 +++------- .../services/blocking/SessionServiceImpl.kt | 2 +- .../models/sessions/SessionEndParamsTest.kt | 45 ++++++++++++- .../services/async/SessionServiceAsyncTest.kt | 1 + .../services/blocking/SessionServiceTest.kt | 1 + 9 files changed, 99 insertions(+), 104 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3a11178..1915416 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml -openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23 -config_hash: 8ec9eaf59304f664cf79f73de1488671 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c6c017cc9ca1fcfe7b3902edfa64fb0420bdb46b1740c7c862e81e2132d4f7c.yml +openapi_spec_hash: 220daf7e8f5897909a6c10e3385386e3 +config_hash: 1f709f8775e13029dc60064ef3a94355 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index 90a656f..6c1186f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -6,9 +6,9 @@ import com.browserbase.api.core.Enum import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams -import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonCreator import java.time.OffsetDateTime @@ -25,9 +25,9 @@ private constructor( private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, + private val body: JsonValue, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, - private val additionalBodyProperties: Map, ) : Params { /** Unique session identifier */ @@ -45,8 +45,7 @@ private constructor( /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - /** Additional body properties to send with the request. */ - fun _additionalBodyProperties(): Map = additionalBodyProperties + fun body(): JsonValue = body /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -58,9 +57,14 @@ private constructor( companion object { - @JvmStatic fun none(): SessionEndParams = builder().build() - - /** Returns a mutable builder for constructing an instance of [SessionEndParams]. */ + /** + * Returns a mutable builder for constructing an instance of [SessionEndParams]. + * + * The following fields are required: + * ```java + * .body() + * ``` + */ @JvmStatic fun builder() = Builder() } @@ -72,9 +76,9 @@ private constructor( private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null + private var body: JsonValue? = null private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() - private var additionalBodyProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionEndParams: SessionEndParams) = apply { @@ -83,9 +87,9 @@ private constructor( xSdkVersion = sessionEndParams.xSdkVersion xSentAt = sessionEndParams.xSentAt xStreamResponse = sessionEndParams.xStreamResponse + body = sessionEndParams.body additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() additionalQueryParams = sessionEndParams.additionalQueryParams.toBuilder() - additionalBodyProperties = sessionEndParams.additionalBodyProperties.toMutableMap() } /** Unique session identifier */ @@ -121,6 +125,8 @@ private constructor( fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) + fun body(body: JsonValue) = apply { this.body = body } + fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() putAllAdditionalHeaders(additionalHeaders) @@ -219,32 +225,17 @@ private constructor( additionalQueryParams.removeAll(keys) } - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - this.additionalBodyProperties.clear() - putAllAdditionalBodyProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - additionalBodyProperties.put(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - this.additionalBodyProperties.putAll(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { - additionalBodyProperties.remove(key) - } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalBodyProperty) - } - /** * Returns an immutable instance of [SessionEndParams]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .body() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): SessionEndParams = SessionEndParams( @@ -253,14 +244,13 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, + checkRequired("body", body), additionalHeaders.build(), additionalQueryParams.build(), - additionalBodyProperties.toImmutable(), ) } - fun _body(): Optional> = - Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + fun _body(): JsonValue = body fun _pathParam(index: Int): String = when (index) { @@ -560,9 +550,9 @@ private constructor( xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && + body == other.body && additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams && - additionalBodyProperties == other.additionalBodyProperties + additionalQueryParams == other.additionalQueryParams } override fun hashCode(): Int = @@ -572,11 +562,11 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, + body, additionalHeaders, additionalQueryParams, - additionalBodyProperties, ) override fun toString() = - "SessionEndParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" + "SessionEndParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index 5c9171e..f2dbbb3 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -89,21 +89,20 @@ interface SessionServiceAsync { ): AsyncStreamResponse /** Terminates the browser session and releases all associated resources. */ - fun end(id: String): CompletableFuture = end(id, SessionEndParams.none()) + fun end(id: String, params: SessionEndParams): CompletableFuture = + end(id, params, RequestOptions.none()) /** @see end */ fun end( id: String, - params: SessionEndParams = SessionEndParams.none(), + params: SessionEndParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ - fun end( - id: String, - params: SessionEndParams = SessionEndParams.none(), - ): CompletableFuture = end(id, params, RequestOptions.none()) + fun end(params: SessionEndParams): CompletableFuture = + end(params, RequestOptions.none()) /** @see end */ fun end( @@ -111,14 +110,6 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture - /** @see end */ - fun end(params: SessionEndParams): CompletableFuture = - end(params, RequestOptions.none()) - - /** @see end */ - fun end(id: String, requestOptions: RequestOptions): CompletableFuture = - end(id, SessionEndParams.none(), requestOptions) - /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ fun execute( id: String, @@ -430,29 +421,19 @@ interface SessionServiceAsync { * Returns a raw HTTP response for `post /v1/sessions/{id}/end`, but is otherwise the same * as [SessionServiceAsync.end]. */ - fun end(id: String): CompletableFuture> = - end(id, SessionEndParams.none()) - - /** @see end */ fun end( id: String, - params: SessionEndParams = SessionEndParams.none(), - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - end(params.toBuilder().id(id).build(), requestOptions) - - /** @see end */ - fun end( - id: String, - params: SessionEndParams = SessionEndParams.none(), + params: SessionEndParams, ): CompletableFuture> = end(id, params, RequestOptions.none()) /** @see end */ fun end( + id: String, params: SessionEndParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> = + end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ fun end(params: SessionEndParams): CompletableFuture> = @@ -460,10 +441,9 @@ interface SessionServiceAsync { /** @see end */ fun end( - id: String, - requestOptions: RequestOptions, - ): CompletableFuture> = - end(id, SessionEndParams.none(), requestOptions) + params: SessionEndParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> /** * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 82062e4..6b354a0 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -250,7 +250,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "end") - .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .body(json(clientOptions.jsonMapper, params._body())) .build() .prepareAsync(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index 0d56e93..2ee1202 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -88,18 +88,18 @@ interface SessionService { ): StreamResponse /** Terminates the browser session and releases all associated resources. */ - fun end(id: String): SessionEndResponse = end(id, SessionEndParams.none()) + fun end(id: String, params: SessionEndParams): SessionEndResponse = + end(id, params, RequestOptions.none()) /** @see end */ fun end( id: String, - params: SessionEndParams = SessionEndParams.none(), + params: SessionEndParams, requestOptions: RequestOptions = RequestOptions.none(), ): SessionEndResponse = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ - fun end(id: String, params: SessionEndParams = SessionEndParams.none()): SessionEndResponse = - end(id, params, RequestOptions.none()) + fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) /** @see end */ fun end( @@ -107,13 +107,6 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): SessionEndResponse - /** @see end */ - fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) - - /** @see end */ - fun end(id: String, requestOptions: RequestOptions): SessionEndResponse = - end(id, SessionEndParams.none(), requestOptions) - /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ fun execute(id: String, params: SessionExecuteParams): SessionExecuteResponse = execute(id, params, RequestOptions.none()) @@ -413,23 +406,22 @@ interface SessionService { * as [SessionService.end]. */ @MustBeClosed - fun end(id: String): HttpResponseFor = end(id, SessionEndParams.none()) + fun end(id: String, params: SessionEndParams): HttpResponseFor = + end(id, params, RequestOptions.none()) /** @see end */ @MustBeClosed fun end( id: String, - params: SessionEndParams = SessionEndParams.none(), + params: SessionEndParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ @MustBeClosed - fun end( - id: String, - params: SessionEndParams = SessionEndParams.none(), - ): HttpResponseFor = end(id, params, RequestOptions.none()) + fun end(params: SessionEndParams): HttpResponseFor = + end(params, RequestOptions.none()) /** @see end */ @MustBeClosed @@ -438,16 +430,6 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor - /** @see end */ - @MustBeClosed - fun end(params: SessionEndParams): HttpResponseFor = - end(params, RequestOptions.none()) - - /** @see end */ - @MustBeClosed - fun end(id: String, requestOptions: RequestOptions): HttpResponseFor = - end(id, SessionEndParams.none(), requestOptions) - /** * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise * the same as [SessionService.execute]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index 4bfce1b..f064761 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -223,7 +223,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "end") - .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .body(json(clientOptions.jsonMapper, params._body())) .build() .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index bc50272..120519f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat @@ -17,12 +18,17 @@ internal class SessionEndParamsTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) + .body(JsonValue.from(mapOf())) .build() } @Test fun pathParams() { - val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() + val params = + SessionEndParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .body(JsonValue.from(mapOf())) + .build() assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param @@ -38,6 +44,7 @@ internal class SessionEndParamsTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) + .body(JsonValue.from(mapOf())) .build() val headers = params._headers() @@ -55,10 +62,44 @@ internal class SessionEndParamsTest { @Test fun headersWithoutOptionalFields() { - val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() + val params = + SessionEndParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .body(JsonValue.from(mapOf())) + .build() val headers = params._headers() assertThat(headers).isEqualTo(Headers.builder().build()) } + + @Test + fun body() { + val params = + SessionEndParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) + .xSdkVersion("3.0.6") + .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) + .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun bodyWithoutOptionalFields() { + val params = + SessionEndParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .body(JsonValue.from(mapOf())) + .build() + + val body = params._body() + + assertThat(body).isEqualTo(JsonValue.from(mapOf())) + } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index f9bc4be..59dd056 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -121,6 +121,7 @@ internal class SessionServiceAsyncTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) + .body(JsonValue.from(mapOf())) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 1bad240..ceec71b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -120,6 +120,7 @@ internal class SessionServiceTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) + .body(JsonValue.from(mapOf())) .build() ) From 181cea3e99ffd07826e85ff7bd8e1ca4205bf604 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 04:53:22 +0000 Subject: [PATCH 047/164] feat(client): add `HttpRequest#url()` method --- .../browserbase/api/core/http/HttpRequest.kt | 30 +++++ .../api/core/http/HttpRequestTest.kt | 110 ++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestTest.kt diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt index f42f44a..280bd51 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.core.http import com.browserbase.api.core.checkRequired import com.browserbase.api.core.toImmutable +import java.net.URLEncoder class HttpRequest private constructor( @@ -13,6 +14,35 @@ private constructor( @get:JvmName("body") val body: HttpRequestBody?, ) { + fun url(): String = buildString { + append(baseUrl) + + pathSegments.forEach { segment -> + if (!endsWith("/")) { + append("/") + } + append(URLEncoder.encode(segment, "UTF-8")) + } + + if (queryParams.isEmpty()) { + return@buildString + } + + append("?") + var isFirst = true + queryParams.keys().forEach { key -> + queryParams.values(key).forEach { value -> + if (!isFirst) { + append("&") + } + append(URLEncoder.encode(key, "UTF-8")) + append("=") + append(URLEncoder.encode(value, "UTF-8")) + isFirst = false + } + } + } + fun toBuilder(): Builder = Builder().from(this) override fun toString(): String = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestTest.kt new file mode 100644 index 0000000..5785890 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestTest.kt @@ -0,0 +1,110 @@ +package com.browserbase.api.core.http + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource + +internal class HttpRequestTest { + + enum class UrlTestCase(val request: HttpRequest, val expectedUrl: String) { + BASE_URL_ONLY( + HttpRequest.builder().method(HttpMethod.GET).baseUrl("https://api.example.com").build(), + expectedUrl = "https://api.example.com", + ), + BASE_URL_WITH_TRAILING_SLASH( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com/") + .build(), + expectedUrl = "https://api.example.com/", + ), + SINGLE_PATH_SEGMENT( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .build(), + expectedUrl = "https://api.example.com/users", + ), + MULTIPLE_PATH_SEGMENTS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegments("users", "123", "profile") + .build(), + expectedUrl = "https://api.example.com/users/123/profile", + ), + PATH_SEGMENT_WITH_SPECIAL_CHARS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("user name") + .build(), + expectedUrl = "https://api.example.com/user+name", + ), + SINGLE_QUERY_PARAM( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParam("limit", "10") + .build(), + expectedUrl = "https://api.example.com/users?limit=10", + ), + MULTIPLE_QUERY_PARAMS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParam("limit", "10") + .putQueryParam("offset", "20") + .build(), + expectedUrl = "https://api.example.com/users?limit=10&offset=20", + ), + QUERY_PARAM_WITH_SPECIAL_CHARS( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("search") + .putQueryParam("q", "hello world") + .build(), + expectedUrl = "https://api.example.com/search?q=hello+world", + ), + MULTIPLE_VALUES_SAME_PARAM( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("users") + .putQueryParams("tags", listOf("admin", "user")) + .build(), + expectedUrl = "https://api.example.com/users?tags=admin&tags=user", + ), + BASE_URL_WITH_TRAILING_SLASH_AND_PATH( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com/") + .addPathSegment("users") + .build(), + expectedUrl = "https://api.example.com/users", + ), + COMPLEX_URL( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl("https://api.example.com") + .addPathSegments("v1", "users", "123") + .putQueryParams("include", listOf("profile", "settings")) + .putQueryParam("format", "json") + .build(), + expectedUrl = + "https://api.example.com/v1/users/123?include=profile&include=settings&format=json", + ), + } + + @ParameterizedTest + @EnumSource + fun url(testCase: UrlTestCase) { + val actualUrl = testCase.request.url() + + assertThat(actualUrl).isEqualTo(testCase.expectedUrl) + } +} From 048d1b065708155a3acd3be855ac9193c98f5925 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 05:02:42 +0000 Subject: [PATCH 048/164] docs: prominently feature MCP server setup in root SDK readmes --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index abb13e3..bc506c4 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,15 @@ The Stagehand Java SDK provides convenient access to the [Stagehand REST API](ht It is generated with [Stainless](https://www.stainless.com/). +## MCP Server + +Use the Stagehand MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. + +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=stagehand-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN0YWdlaGFuZC1tY3AiXX0) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22stagehand-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22stagehand-mcp%22%5D%7D) + +> Note: You may need to set environment variables in your MCP client. + The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.4.0). From 657265024b64bb68ac65326267bef8f68c944ad0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 6 Jan 2026 19:34:03 +0000 Subject: [PATCH 049/164] feat: Added optional param to force empty object --- .stats.yml | 4 +- .../api/models/sessions/SessionEndParams.kt | 186 +++++++++++++++--- .../api/services/async/SessionServiceAsync.kt | 44 +++-- .../api/services/blocking/SessionService.kt | 36 +++- .../models/sessions/SessionEndParamsTest.kt | 28 +-- .../services/async/SessionServiceAsyncTest.kt | 2 +- .../services/blocking/SessionServiceTest.kt | 2 +- 7 files changed, 233 insertions(+), 69 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1915416..f4f95e8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2c6c017cc9ca1fcfe7b3902edfa64fb0420bdb46b1740c7c862e81e2132d4f7c.yml -openapi_spec_hash: 220daf7e8f5897909a6c10e3385386e3 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-39cd9547d16412cf0568f6ce2ad8d43805dffe65bde830beeff630b903ae3b38.yml +openapi_spec_hash: 9cd7c9fefa686f9711392782d948470f config_hash: 1f709f8775e13029dc60064ef3a94355 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index 6c1186f..e10e438 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -3,16 +3,21 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.Enum +import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params -import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty import java.time.OffsetDateTime import java.time.format.DateTimeFormatter +import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -25,7 +30,7 @@ private constructor( private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, - private val body: JsonValue, + private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { @@ -45,7 +50,9 @@ private constructor( /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun body(): JsonValue = body + fun __forceBody(): JsonValue = body.__forceBody() + + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -57,14 +64,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [SessionEndParams]. - * - * The following fields are required: - * ```java - * .body() - * ``` - */ + @JvmStatic fun none(): SessionEndParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionEndParams]. */ @JvmStatic fun builder() = Builder() } @@ -76,7 +78,7 @@ private constructor( private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null - private var body: JsonValue? = null + private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() @@ -87,7 +89,7 @@ private constructor( xSdkVersion = sessionEndParams.xSdkVersion xSentAt = sessionEndParams.xSentAt xStreamResponse = sessionEndParams.xStreamResponse - body = sessionEndParams.body + body = sessionEndParams.body.toBuilder() additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() additionalQueryParams = sessionEndParams.additionalQueryParams.toBuilder() } @@ -125,7 +127,35 @@ private constructor( fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - fun body(body: JsonValue) = apply { this.body = body } + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [_forceBody] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + fun _forceBody(_forceBody: JsonValue) = apply { body._forceBody(_forceBody) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -229,13 +259,6 @@ private constructor( * Returns an immutable instance of [SessionEndParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .body() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): SessionEndParams = SessionEndParams( @@ -244,13 +267,13 @@ private constructor( xSdkVersion, xSentAt, xStreamResponse, - checkRequired("body", body), + body.build(), additionalHeaders.build(), additionalQueryParams.build(), ) } - fun _body(): JsonValue = body + fun _body(): Body = body fun _pathParam(index: Int): String = when (index) { @@ -271,6 +294,123 @@ private constructor( override fun _queryParams(): QueryParams = additionalQueryParams + class Body + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val _forceBody: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("_forceBody") @ExcludeMissing _forceBody: JsonValue = JsonMissing.of() + ) : this(_forceBody, mutableMapOf()) + + @JsonProperty("_forceBody") @ExcludeMissing fun __forceBody(): JsonValue = _forceBody + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Body]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var _forceBody: JsonValue = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + _forceBody = body._forceBody + additionalProperties = body.additionalProperties.toMutableMap() + } + + fun _forceBody(_forceBody: JsonValue) = apply { this._forceBody = _forceBody } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Body = Body(_forceBody, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = 0 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Body && + _forceBody == other._forceBody && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(_forceBody, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{_forceBody=$_forceBody, additionalProperties=$additionalProperties}" + } + /** Client SDK language */ class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index f2dbbb3..5c9171e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -89,20 +89,21 @@ interface SessionServiceAsync { ): AsyncStreamResponse /** Terminates the browser session and releases all associated resources. */ - fun end(id: String, params: SessionEndParams): CompletableFuture = - end(id, params, RequestOptions.none()) + fun end(id: String): CompletableFuture = end(id, SessionEndParams.none()) /** @see end */ fun end( id: String, - params: SessionEndParams, + params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ - fun end(params: SessionEndParams): CompletableFuture = - end(params, RequestOptions.none()) + fun end( + id: String, + params: SessionEndParams = SessionEndParams.none(), + ): CompletableFuture = end(id, params, RequestOptions.none()) /** @see end */ fun end( @@ -110,6 +111,14 @@ interface SessionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see end */ + fun end(params: SessionEndParams): CompletableFuture = + end(params, RequestOptions.none()) + + /** @see end */ + fun end(id: String, requestOptions: RequestOptions): CompletableFuture = + end(id, SessionEndParams.none(), requestOptions) + /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ fun execute( id: String, @@ -421,19 +430,29 @@ interface SessionServiceAsync { * Returns a raw HTTP response for `post /v1/sessions/{id}/end`, but is otherwise the same * as [SessionServiceAsync.end]. */ + fun end(id: String): CompletableFuture> = + end(id, SessionEndParams.none()) + + /** @see end */ fun end( id: String, - params: SessionEndParams, + params: SessionEndParams = SessionEndParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - end(id, params, RequestOptions.none()) + end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ fun end( id: String, + params: SessionEndParams = SessionEndParams.none(), + ): CompletableFuture> = + end(id, params, RequestOptions.none()) + + /** @see end */ + fun end( params: SessionEndParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = - end(params.toBuilder().id(id).build(), requestOptions) + ): CompletableFuture> /** @see end */ fun end(params: SessionEndParams): CompletableFuture> = @@ -441,9 +460,10 @@ interface SessionServiceAsync { /** @see end */ fun end( - params: SessionEndParams, - requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + id: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + end(id, SessionEndParams.none(), requestOptions) /** * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index 2ee1202..0d56e93 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -88,18 +88,18 @@ interface SessionService { ): StreamResponse /** Terminates the browser session and releases all associated resources. */ - fun end(id: String, params: SessionEndParams): SessionEndResponse = - end(id, params, RequestOptions.none()) + fun end(id: String): SessionEndResponse = end(id, SessionEndParams.none()) /** @see end */ fun end( id: String, - params: SessionEndParams, + params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): SessionEndResponse = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ - fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) + fun end(id: String, params: SessionEndParams = SessionEndParams.none()): SessionEndResponse = + end(id, params, RequestOptions.none()) /** @see end */ fun end( @@ -107,6 +107,13 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): SessionEndResponse + /** @see end */ + fun end(params: SessionEndParams): SessionEndResponse = end(params, RequestOptions.none()) + + /** @see end */ + fun end(id: String, requestOptions: RequestOptions): SessionEndResponse = + end(id, SessionEndParams.none(), requestOptions) + /** Runs an autonomous AI agent that can perform complex multi-step browser tasks. */ fun execute(id: String, params: SessionExecuteParams): SessionExecuteResponse = execute(id, params, RequestOptions.none()) @@ -406,22 +413,23 @@ interface SessionService { * as [SessionService.end]. */ @MustBeClosed - fun end(id: String, params: SessionEndParams): HttpResponseFor = - end(id, params, RequestOptions.none()) + fun end(id: String): HttpResponseFor = end(id, SessionEndParams.none()) /** @see end */ @MustBeClosed fun end( id: String, - params: SessionEndParams, + params: SessionEndParams = SessionEndParams.none(), requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor = end(params.toBuilder().id(id).build(), requestOptions) /** @see end */ @MustBeClosed - fun end(params: SessionEndParams): HttpResponseFor = - end(params, RequestOptions.none()) + fun end( + id: String, + params: SessionEndParams = SessionEndParams.none(), + ): HttpResponseFor = end(id, params, RequestOptions.none()) /** @see end */ @MustBeClosed @@ -430,6 +438,16 @@ interface SessionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see end */ + @MustBeClosed + fun end(params: SessionEndParams): HttpResponseFor = + end(params, RequestOptions.none()) + + /** @see end */ + @MustBeClosed + fun end(id: String, requestOptions: RequestOptions): HttpResponseFor = + end(id, SessionEndParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/{id}/agentExecute`, but is otherwise * the same as [SessionService.execute]. diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 120519f..3150dad 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -18,17 +18,13 @@ internal class SessionEndParamsTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - .body(JsonValue.from(mapOf())) + ._forceBody(JsonValue.from(mapOf())) .build() } @Test fun pathParams() { - val params = - SessionEndParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .body(JsonValue.from(mapOf())) - .build() + val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") // out-of-bound path param @@ -44,7 +40,7 @@ internal class SessionEndParamsTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - .body(JsonValue.from(mapOf())) + ._forceBody(JsonValue.from(mapOf())) .build() val headers = params._headers() @@ -62,11 +58,7 @@ internal class SessionEndParamsTest { @Test fun headersWithoutOptionalFields() { - val params = - SessionEndParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .body(JsonValue.from(mapOf())) - .build() + val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val headers = params._headers() @@ -82,24 +74,18 @@ internal class SessionEndParamsTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - .body(JsonValue.from(mapOf())) + ._forceBody(JsonValue.from(mapOf())) .build() val body = params._body() - assertThat(body).isEqualTo(JsonValue.from(mapOf())) + assertThat(body.__forceBody()).isEqualTo(JsonValue.from(mapOf())) } @Test fun bodyWithoutOptionalFields() { - val params = - SessionEndParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .body(JsonValue.from(mapOf())) - .build() + val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() val body = params._body() - - assertThat(body).isEqualTo(JsonValue.from(mapOf())) } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 59dd056..8a517d2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -121,7 +121,7 @@ internal class SessionServiceAsyncTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - .body(JsonValue.from(mapOf())) + ._forceBody(JsonValue.from(mapOf())) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index ceec71b..1a94b1f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -120,7 +120,7 @@ internal class SessionServiceTest { .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - .body(JsonValue.from(mapOf())) + ._forceBody(JsonValue.from(mapOf())) .build() ) From 65ca0838d53eaf5339abd169ef151e19c7a77752 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:47:23 +0000 Subject: [PATCH 050/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index f4f95e8..b120b66 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-39cd9547d16412cf0568f6ce2ad8d43805dffe65bde830beeff630b903ae3b38.yml openapi_spec_hash: 9cd7c9fefa686f9711392782d948470f -config_hash: 1f709f8775e13029dc60064ef3a94355 +config_hash: 3c21550e2c94cad4339d3093d794beb0 From e3ca44d1918b4b3fa6eeca49db9118ac92c65835 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:53:49 +0000 Subject: [PATCH 051/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index da59f99..2aca35a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.4.0" + ".": "0.5.0" } \ No newline at end of file diff --git a/README.md b/README.md index bc506c4..472741e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.4.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.4.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.4.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.5.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.5.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.5.0) @@ -22,7 +22,7 @@ Use the Stagehand MCP Server to enable AI assistants to interact with this API, -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.4.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.5.0). @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.4.0") +implementation("com.browserbase.api:stagehand-java:0.5.0") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.browserbase.api:stagehand-java:0.4.0") com.browserbase.api stagehand-java - 0.4.0 + 0.5.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index bd9f794..0db3fe0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.4.0" // x-release-please-version + version = "0.5.0" // x-release-please-version } subprojects { From 4ce3494a5dc7f7d1d3fdb48c06683341d5057a23 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 04:37:47 +0000 Subject: [PATCH 052/164] feat(client): allow configuring dispatcher executor service --- .../api/client/okhttp/OkHttpClient.kt | 9 ++++++++ .../client/okhttp/StagehandOkHttpClient.kt | 22 +++++++++++++++++++ .../okhttp/StagehandOkHttpClientAsync.kt | 22 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index c03dd12..116714c 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -15,11 +15,13 @@ import java.net.Proxy import java.time.Duration import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -202,6 +204,7 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -212,6 +215,10 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + fun sslSocketFactory(sslSocketFactory: SSLSocketFactory?) = apply { this.sslSocketFactory = sslSocketFactory } @@ -233,6 +240,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien .callTimeout(timeout.request()) .proxy(proxy) .apply { + dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index 0588b0d..f5d6ff5 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -18,6 +18,7 @@ import java.time.Clock import java.time.Duration import java.util.Optional import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -46,11 +47,31 @@ class StagehandOkHttpClient private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -320,6 +341,7 @@ class StagehandOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 7f2ea56..9f8bbb7 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -18,6 +18,7 @@ import java.time.Clock import java.time.Duration import java.util.Optional import java.util.concurrent.Executor +import java.util.concurrent.ExecutorService import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager @@ -46,11 +47,31 @@ class StagehandOkHttpClientAsync private constructor() { class Builder internal constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() + private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null + /** + * The executor service to use for running HTTP requests. + * + * Defaults to OkHttp's + * [default executor service](https://github.com/square/okhttp/blob/ace792f443b2ffb17974f5c0d1cecdf589309f26/okhttp/src/commonJvmAndroid/kotlin/okhttp3/Dispatcher.kt#L98-L104). + * + * This class takes ownership of the executor service and shuts it down when closed. + */ + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { + this.dispatcherExecutorService = dispatcherExecutorService + } + + /** + * Alias for calling [Builder.dispatcherExecutorService] with + * `dispatcherExecutorService.orElse(null)`. + */ + fun dispatcherExecutorService(dispatcherExecutorService: Optional) = + dispatcherExecutorService(dispatcherExecutorService.getOrNull()) + fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ @@ -320,6 +341,7 @@ class StagehandOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) .hostnameVerifier(hostnameVerifier) From 32350c56dbb75dc0c3dadab40c09b121b03b4bd5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 10 Jan 2026 00:00:30 +0000 Subject: [PATCH 053/164] feat: Removed requiring x-language and x-sdk-version from openapi spec --- .stats.yml | 4 +- .../api/models/sessions/SessionActParams.kt | 179 +----------------- .../api/models/sessions/SessionEndParams.kt | 179 +----------------- .../models/sessions/SessionExecuteParams.kt | 179 +----------------- .../models/sessions/SessionExtractParams.kt | 179 +----------------- .../models/sessions/SessionNavigateParams.kt | 179 +----------------- .../models/sessions/SessionObserveParams.kt | 179 +----------------- .../api/models/sessions/SessionStartParams.kt | 178 +---------------- .../models/sessions/SessionActParamsTest.kt | 8 - .../models/sessions/SessionEndParamsTest.kt | 8 - .../sessions/SessionExecuteParamsTest.kt | 8 - .../sessions/SessionExtractParamsTest.kt | 8 - .../sessions/SessionNavigateParamsTest.kt | 8 - .../sessions/SessionObserveParamsTest.kt | 8 - .../models/sessions/SessionStartParamsTest.kt | 8 - .../api/services/ErrorHandlingTest.kt | 34 ---- .../api/services/ServiceParamsTest.kt | 4 - .../services/async/SessionServiceAsyncTest.kt | 22 --- .../services/blocking/SessionServiceTest.kt | 22 --- 19 files changed, 16 insertions(+), 1378 deletions(-) diff --git a/.stats.yml b/.stats.yml index b120b66..f53d855 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-39cd9547d16412cf0568f6ce2ad8d43805dffe65bde830beeff630b903ae3b38.yml -openapi_spec_hash: 9cd7c9fefa686f9711392782d948470f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1705ff86e7ec80d6be2ddbb0e3cbee821f3e95d68fa6a48c790f586e3470e678.yml +openapi_spec_hash: cf0d4dad078a7f7c1256b437e349b911 config_hash: 3c21550e2c94cad4339d3093d794beb0 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index a37780c..182931c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -39,8 +39,6 @@ import kotlin.jvm.optionals.getOrNull class SessionActParams private constructor( private val id: String?, - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -51,12 +49,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -133,8 +125,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -144,8 +134,6 @@ private constructor( @JvmSynthetic internal fun from(sessionActParams: SessionActParams) = apply { id = sessionActParams.id - xLanguage = sessionActParams.xLanguage - xSdkVersion = sessionActParams.xSdkVersion xSentAt = sessionActParams.xSentAt xStreamResponse = sessionActParams.xStreamResponse body = sessionActParams.body.toBuilder() @@ -159,18 +147,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -367,8 +343,6 @@ private constructor( fun build(): SessionActParams = SessionActParams( id, - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -388,8 +362,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -1142,142 +1114,6 @@ private constructor( "Options{model=$model, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1417,8 +1253,6 @@ private constructor( return other is SessionActParams && id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -1427,17 +1261,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionActParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionActParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index e10e438..c861cc2 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -26,8 +26,6 @@ import kotlin.jvm.optionals.getOrNull class SessionEndParams private constructor( private val id: String?, - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -38,12 +36,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -74,8 +66,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -85,8 +75,6 @@ private constructor( @JvmSynthetic internal fun from(sessionEndParams: SessionEndParams) = apply { id = sessionEndParams.id - xLanguage = sessionEndParams.xLanguage - xSdkVersion = sessionEndParams.xSdkVersion xSentAt = sessionEndParams.xSentAt xStreamResponse = sessionEndParams.xStreamResponse body = sessionEndParams.body.toBuilder() @@ -100,18 +88,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -263,8 +239,6 @@ private constructor( fun build(): SessionEndParams = SessionEndParams( id, - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -284,8 +258,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -411,142 +383,6 @@ private constructor( "Body{_forceBody=$_forceBody, additionalProperties=$additionalProperties}" } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -686,8 +522,6 @@ private constructor( return other is SessionEndParams && id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -696,17 +530,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionEndParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionEndParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 8cb0da8..813b432 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -27,8 +27,6 @@ import kotlin.jvm.optionals.getOrNull class SessionExecuteParams private constructor( private val id: String?, - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -39,12 +37,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -120,8 +112,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -131,8 +121,6 @@ private constructor( @JvmSynthetic internal fun from(sessionExecuteParams: SessionExecuteParams) = apply { id = sessionExecuteParams.id - xLanguage = sessionExecuteParams.xLanguage - xSdkVersion = sessionExecuteParams.xSdkVersion xSentAt = sessionExecuteParams.xSentAt xStreamResponse = sessionExecuteParams.xStreamResponse body = sessionExecuteParams.body.toBuilder() @@ -146,18 +134,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -356,8 +332,6 @@ private constructor( fun build(): SessionExecuteParams = SessionExecuteParams( id, - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -377,8 +351,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -1290,142 +1262,6 @@ private constructor( "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1565,8 +1401,6 @@ private constructor( return other is SessionExecuteParams && id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -1575,17 +1409,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionExecuteParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionExecuteParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 3a5c4bd..3ef55df 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -27,8 +27,6 @@ import kotlin.jvm.optionals.getOrNull class SessionExtractParams private constructor( private val id: String?, - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -39,12 +37,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -131,8 +123,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -142,8 +132,6 @@ private constructor( @JvmSynthetic internal fun from(sessionExtractParams: SessionExtractParams) = apply { id = sessionExtractParams.id - xLanguage = sessionExtractParams.xLanguage - xSdkVersion = sessionExtractParams.xSdkVersion xSentAt = sessionExtractParams.xSentAt xStreamResponse = sessionExtractParams.xStreamResponse body = sessionExtractParams.body.toBuilder() @@ -157,18 +145,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -365,8 +341,6 @@ private constructor( fun build(): SessionExtractParams = SessionExtractParams( id, - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -386,8 +360,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -976,142 +948,6 @@ private constructor( override fun toString() = "Schema{additionalProperties=$additionalProperties}" } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1251,8 +1087,6 @@ private constructor( return other is SessionExtractParams && id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -1261,17 +1095,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionExtractParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionExtractParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index 112be92..2d63849 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -27,8 +27,6 @@ import kotlin.jvm.optionals.getOrNull class SessionNavigateParams private constructor( private val id: String?, - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -39,12 +37,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -136,8 +128,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -147,8 +137,6 @@ private constructor( @JvmSynthetic internal fun from(sessionNavigateParams: SessionNavigateParams) = apply { id = sessionNavigateParams.id - xLanguage = sessionNavigateParams.xLanguage - xSdkVersion = sessionNavigateParams.xSdkVersion xSentAt = sessionNavigateParams.xSentAt xStreamResponse = sessionNavigateParams.xStreamResponse body = sessionNavigateParams.body.toBuilder() @@ -162,18 +150,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -379,8 +355,6 @@ private constructor( fun build(): SessionNavigateParams = SessionNavigateParams( id, - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -400,8 +374,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -1039,142 +1011,6 @@ private constructor( "Options{referer=$referer, timeout=$timeout, waitUntil=$waitUntil, additionalProperties=$additionalProperties}" } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1314,8 +1150,6 @@ private constructor( return other is SessionNavigateParams && id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -1324,17 +1158,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionNavigateParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionNavigateParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 66c3b91..37efafd 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -28,8 +28,6 @@ import kotlin.jvm.optionals.getOrNull class SessionObserveParams private constructor( private val id: String?, - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -40,12 +38,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -117,8 +109,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -128,8 +118,6 @@ private constructor( @JvmSynthetic internal fun from(sessionObserveParams: SessionObserveParams) = apply { id = sessionObserveParams.id - xLanguage = sessionObserveParams.xLanguage - xSdkVersion = sessionObserveParams.xSdkVersion xSentAt = sessionObserveParams.xSentAt xStreamResponse = sessionObserveParams.xStreamResponse body = sessionObserveParams.body.toBuilder() @@ -143,18 +131,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -339,8 +315,6 @@ private constructor( fun build(): SessionObserveParams = SessionObserveParams( id, - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -360,8 +334,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -816,142 +788,6 @@ private constructor( "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1091,8 +927,6 @@ private constructor( return other is SessionObserveParams && id == other.id && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -1101,17 +935,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - id, - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionObserveParams{id=$id, xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionObserveParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 3a7009b..2d3ece2 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -42,8 +42,6 @@ import kotlin.jvm.optionals.getOrNull */ class SessionStartParams private constructor( - private val xLanguage: XLanguage?, - private val xSdkVersion: String?, private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, @@ -51,12 +49,6 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - /** Client SDK language */ - fun xLanguage(): Optional = Optional.ofNullable(xLanguage) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(): Optional = Optional.ofNullable(xSdkVersion) - /** ISO timestamp when request was sent */ fun xSentAt(): Optional = Optional.ofNullable(xSentAt) @@ -254,8 +246,6 @@ private constructor( /** A builder for [SessionStartParams]. */ class Builder internal constructor() { - private var xLanguage: XLanguage? = null - private var xSdkVersion: String? = null private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() @@ -264,8 +254,6 @@ private constructor( @JvmSynthetic internal fun from(sessionStartParams: SessionStartParams) = apply { - xLanguage = sessionStartParams.xLanguage - xSdkVersion = sessionStartParams.xSdkVersion xSentAt = sessionStartParams.xSentAt xStreamResponse = sessionStartParams.xStreamResponse body = sessionStartParams.body.toBuilder() @@ -273,18 +261,6 @@ private constructor( additionalQueryParams = sessionStartParams.additionalQueryParams.toBuilder() } - /** Client SDK language */ - fun xLanguage(xLanguage: XLanguage?) = apply { this.xLanguage = xLanguage } - - /** Alias for calling [Builder.xLanguage] with `xLanguage.orElse(null)`. */ - fun xLanguage(xLanguage: Optional) = xLanguage(xLanguage.getOrNull()) - - /** Version of the Stagehand SDK */ - fun xSdkVersion(xSdkVersion: String?) = apply { this.xSdkVersion = xSdkVersion } - - /** Alias for calling [Builder.xSdkVersion] with `xSdkVersion.orElse(null)`. */ - fun xSdkVersion(xSdkVersion: Optional) = xSdkVersion(xSdkVersion.getOrNull()) - /** ISO timestamp when request was sent */ fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } @@ -594,8 +570,6 @@ private constructor( */ fun build(): SessionStartParams = SessionStartParams( - xLanguage, - xSdkVersion, xSentAt, xStreamResponse, body.build(), @@ -609,8 +583,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xLanguage?.let { put("x-language", it.toString()) } - xSdkVersion?.let { put("x-sdk-version", it) } xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) @@ -7190,142 +7162,6 @@ private constructor( override fun toString() = value.toString() } - /** Client SDK language */ - class XLanguage @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is on an - * older version than the API, then the API may respond with new members that the SDK is - * unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val TYPESCRIPT = of("typescript") - - @JvmField val PYTHON = of("python") - - @JvmField val PLAYGROUND = of("playground") - - @JvmStatic fun of(value: String) = XLanguage(JsonField.of(value)) - } - - /** An enum containing [XLanguage]'s known values. */ - enum class Known { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - } - - /** - * An enum containing [XLanguage]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [XLanguage] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if the - * SDK is on an older version than the API, then the API may respond with new members that - * the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - TYPESCRIPT, - PYTHON, - PLAYGROUND, - /** - * An enum member indicating that [XLanguage] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] - * if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you want - * to throw for the unknown case. - */ - fun value(): Value = - when (this) { - TYPESCRIPT -> Value.TYPESCRIPT - PYTHON -> Value.PYTHON - PLAYGROUND -> Value.PLAYGROUND - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and don't - * want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - TYPESCRIPT -> Known.TYPESCRIPT - PYTHON -> Known.PYTHON - PLAYGROUND -> Known.PLAYGROUND - else -> throw StagehandInvalidDataException("Unknown XLanguage: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for debugging - * and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have the - * expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): XLanguage = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is XLanguage && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -7464,8 +7300,6 @@ private constructor( } return other is SessionStartParams && - xLanguage == other.xLanguage && - xSdkVersion == other.xSdkVersion && xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && @@ -7474,16 +7308,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash( - xLanguage, - xSdkVersion, - xSentAt, - xStreamResponse, - body, - additionalHeaders, - additionalQueryParams, - ) + Objects.hash(xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionStartParams{xLanguage=$xLanguage, xSdkVersion=$xSdkVersion, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionStartParams{xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 9c19cb7..54acc4f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -14,8 +14,6 @@ internal class SessionActParamsTest { fun create() { SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") @@ -52,8 +50,6 @@ internal class SessionActParamsTest { val params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") @@ -76,8 +72,6 @@ internal class SessionActParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -102,8 +96,6 @@ internal class SessionActParamsTest { val params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 3150dad..9081b87 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -14,8 +14,6 @@ internal class SessionEndParamsTest { fun create() { SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) @@ -36,8 +34,6 @@ internal class SessionEndParamsTest { val params = SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) @@ -48,8 +44,6 @@ internal class SessionEndParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -70,8 +64,6 @@ internal class SessionEndParamsTest { val params = SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 8869791..2064b33 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -13,8 +13,6 @@ internal class SessionExecuteParamsTest { fun create() { SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( @@ -63,8 +61,6 @@ internal class SessionExecuteParamsTest { val params = SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( @@ -92,8 +88,6 @@ internal class SessionExecuteParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -125,8 +119,6 @@ internal class SessionExecuteParamsTest { val params = SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index b8d0a00..54b80a6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -14,8 +14,6 @@ internal class SessionExtractParamsTest { fun create() { SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") @@ -50,8 +48,6 @@ internal class SessionExtractParamsTest { val params = SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") @@ -75,8 +71,6 @@ internal class SessionExtractParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -98,8 +92,6 @@ internal class SessionExtractParamsTest { val params = SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt index 169d089..3616da2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -13,8 +13,6 @@ internal class SessionNavigateParamsTest { fun create() { SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") @@ -48,8 +46,6 @@ internal class SessionNavigateParamsTest { val params = SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") @@ -69,8 +65,6 @@ internal class SessionNavigateParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -95,8 +89,6 @@ internal class SessionNavigateParamsTest { val params = SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index db03460..eeb111b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -13,8 +13,6 @@ internal class SessionObserveParamsTest { fun create() { SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") @@ -44,8 +42,6 @@ internal class SessionObserveParamsTest { val params = SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") @@ -64,8 +60,6 @@ internal class SessionObserveParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -87,8 +81,6 @@ internal class SessionObserveParamsTest { val params = SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 765a962..2136f9f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -13,8 +13,6 @@ internal class SessionStartParamsTest { @Test fun create() { SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -161,8 +159,6 @@ internal class SessionStartParamsTest { fun headers() { val params = SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -313,8 +309,6 @@ internal class SessionStartParamsTest { assertThat(headers) .isEqualTo( Headers.builder() - .put("x-language", "typescript") - .put("x-sdk-version", "3.0.6") .put("x-sent-at", "2025-01-15T10:30:00Z") .put("x-stream-response", "true") .build() @@ -334,8 +328,6 @@ internal class SessionStartParamsTest { fun body() { val params = SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index f704c1a..f8c2c3c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -75,8 +75,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -254,8 +252,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -433,8 +429,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -612,8 +606,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -791,8 +783,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -970,8 +960,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -1149,8 +1137,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -1328,8 +1314,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -1507,8 +1491,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -1686,8 +1668,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -1865,8 +1845,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -2044,8 +2022,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -2223,8 +2199,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -2402,8 +2376,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -2581,8 +2553,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -2760,8 +2730,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -2937,8 +2905,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 2243046..1304d88 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -48,8 +48,6 @@ internal class ServiceParamsTest { sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") @@ -216,8 +214,6 @@ internal class ServiceParamsTest { sessionService.act( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 8a517d2..0c92027 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -36,8 +36,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.act( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") @@ -76,8 +74,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.actStreaming( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") @@ -117,8 +113,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.end( SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) @@ -145,8 +139,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.execute( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( @@ -190,8 +182,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.executeStreaming( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( @@ -236,8 +226,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.extract( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") @@ -277,8 +265,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.extractStreaming( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") @@ -319,8 +305,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.navigate( SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") @@ -356,8 +340,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.observe( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") @@ -392,8 +374,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.observeStreaming( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") @@ -428,8 +408,6 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 1a94b1f..68005ff 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -36,8 +36,6 @@ internal class SessionServiceTest { sessionService.act( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") @@ -75,8 +73,6 @@ internal class SessionServiceTest { sessionService.actStreaming( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionActParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") @@ -116,8 +112,6 @@ internal class SessionServiceTest { sessionService.end( SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionEndParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) @@ -143,8 +137,6 @@ internal class SessionServiceTest { sessionService.execute( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( @@ -187,8 +179,6 @@ internal class SessionServiceTest { sessionService.executeStreaming( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExecuteParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( @@ -233,8 +223,6 @@ internal class SessionServiceTest { sessionService.extract( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") @@ -273,8 +261,6 @@ internal class SessionServiceTest { sessionService.extractStreaming( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionExtractParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") @@ -315,8 +301,6 @@ internal class SessionServiceTest { sessionService.navigate( SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionNavigateParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") @@ -351,8 +335,6 @@ internal class SessionServiceTest { sessionService.observe( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") @@ -386,8 +368,6 @@ internal class SessionServiceTest { sessionService.observeStreaming( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xLanguage(SessionObserveParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") @@ -422,8 +402,6 @@ internal class SessionServiceTest { val response = sessionService.start( SessionStartParams.builder() - .xLanguage(SessionStartParams.XLanguage.TYPESCRIPT) - .xSdkVersion("3.0.6") .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("gpt-4o") From 758e2d9d8ed5a60e91242e22ae4d2f46e9413934 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 20:09:13 +0000 Subject: [PATCH 054/164] feat: Using provider/model syntax in modelName examples within openapi spec --- .stats.yml | 6 ++-- .../api/models/sessions/ModelConfig.kt | 4 +-- .../api/models/sessions/ModelConfigTest.kt | 4 +-- .../models/sessions/SessionStartParamsTest.kt | 14 ++++---- .../api/services/ErrorHandlingTest.kt | 34 +++++++++---------- .../api/services/ServiceParamsTest.kt | 2 +- .../services/async/SessionServiceAsyncTest.kt | 2 +- .../services/blocking/SessionServiceTest.kt | 2 +- 8 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.stats.yml b/.stats.yml index f53d855..93fe5d1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1705ff86e7ec80d6be2ddbb0e3cbee821f3e95d68fa6a48c790f586e3470e678.yml -openapi_spec_hash: cf0d4dad078a7f7c1256b437e349b911 -config_hash: 3c21550e2c94cad4339d3093d794beb0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-119383e808f394a7676e901bac8b97b6d7402d187d03452fd8d62b31d4085580.yml +openapi_spec_hash: 8a8d7be19d95f849098690863fe9a71a +config_hash: 1f709f8775e13029dc60064ef3a94355 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index bfbf0aa..ce0785b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -243,7 +243,7 @@ private constructor( ) : this(modelName, apiKey, baseUrl, provider, mutableMapOf()) /** - * Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus') + * Model name string (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -345,7 +345,7 @@ private constructor( additionalProperties = modelConfigObject.additionalProperties.toMutableMap() } - /** Model name string without prefix (e.g., 'gpt-5-nano', 'claude-4.5-opus') */ + /** Model name string (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') */ fun modelName(modelName: String) = modelName(JsonField.of(modelName)) /** diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index fc5ea48..db47f8d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -40,7 +40,7 @@ internal class ModelConfigTest { fun ofModelConfigObject() { val modelConfigObject = ModelConfig.ModelConfigObject.builder() - .modelName("gpt-5-nano") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) @@ -58,7 +58,7 @@ internal class ModelConfigTest { val modelConfig = ModelConfig.ofModelConfigObject( ModelConfig.ModelConfigObject.builder() - .modelName("gpt-5-nano") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 2136f9f..4e4e0dc 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -15,7 +15,7 @@ internal class SessionStartParamsTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -161,7 +161,7 @@ internal class SessionStartParamsTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -317,7 +317,7 @@ internal class SessionStartParamsTest { @Test fun headersWithoutOptionalFields() { - val params = SessionStartParams.builder().modelName("gpt-4o").build() + val params = SessionStartParams.builder().modelName("openai/gpt-4o").build() val headers = params._headers() @@ -330,7 +330,7 @@ internal class SessionStartParamsTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -475,7 +475,7 @@ internal class SessionStartParamsTest { val body = params._body() - assertThat(body.modelName()).isEqualTo("gpt-4o") + assertThat(body.modelName()).isEqualTo("openai/gpt-4o") assertThat(body.actTimeoutMs()).contains(0.0) assertThat(body.browser()) .contains( @@ -618,10 +618,10 @@ internal class SessionStartParamsTest { @Test fun bodyWithoutOptionalFields() { - val params = SessionStartParams.builder().modelName("gpt-4o").build() + val params = SessionStartParams.builder().modelName("openai/gpt-4o").build() val body = params._body() - assertThat(body.modelName()).isEqualTo("gpt-4o") + assertThat(body.modelName()).isEqualTo("openai/gpt-4o") } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index f8c2c3c..6dab5ba 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -77,7 +77,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -254,7 +254,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -431,7 +431,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -608,7 +608,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -785,7 +785,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -962,7 +962,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1139,7 +1139,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1316,7 +1316,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1493,7 +1493,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1670,7 +1670,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1847,7 +1847,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2024,7 +2024,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2201,7 +2201,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2378,7 +2378,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2555,7 +2555,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2732,7 +2732,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2907,7 +2907,7 @@ internal class ErrorHandlingTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 1304d88..33f0206 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -50,7 +50,7 @@ internal class ServiceParamsTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 0c92027..d457ad4 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -410,7 +410,7 @@ internal class SessionServiceAsyncTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 68005ff..b7d0e6b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -404,7 +404,7 @@ internal class SessionServiceTest { SessionStartParams.builder() .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("gpt-4o") + .modelName("openai/gpt-4o") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() From 3eb3f8fbeaf28c70b1def0a364c1cdf55757650d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 00:47:35 +0000 Subject: [PATCH 055/164] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 93fe5d1..31ed2c4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-119383e808f394a7676e901bac8b97b6d7402d187d03452fd8d62b31d4085580.yml -openapi_spec_hash: 8a8d7be19d95f849098690863fe9a71a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-419940ce988c43313660d30a5bb5b5c2d89b3b19a0f80fe050331e0f4e8c58d2.yml +openapi_spec_hash: a621ca69697ebba7286cbf9e475c46ad config_hash: 1f709f8775e13029dc60064ef3a94355 From e27c30d1c703bf22b9ec4b92112b18549fa870c9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 00:59:22 +0000 Subject: [PATCH 056/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 31ed2c4..a03dd75 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-419940ce988c43313660d30a5bb5b5c2d89b3b19a0f80fe050331e0f4e8c58d2.yml openapi_spec_hash: a621ca69697ebba7286cbf9e475c46ad -config_hash: 1f709f8775e13029dc60064ef3a94355 +config_hash: 74111faa0876db6b053526281c444498 From fcdb3d7ff864f035a82ac526afef3fc8b6c1fe1b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 07:47:39 +0000 Subject: [PATCH 057/164] chore(internal): support uploading Maven repo artifacts to stainless package server --- .github/workflows/ci.yml | 18 ++++ .../main/kotlin/stagehand.publish.gradle.kts | 8 ++ scripts/upload-artifacts | 96 +++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100755 scripts/upload-artifacts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7186ff6..e136c7c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,9 @@ jobs: build: timeout-minutes: 15 name: build + permissions: + contents: read + id-token: write runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork @@ -61,6 +64,21 @@ jobs: - name: Build SDK run: ./scripts/build + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/stagehand-java' + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Build and upload Maven artifacts + if: github.repository == 'stainless-sdks/stagehand-java' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + PROJECT: stagehand-java + run: ./scripts/upload-artifacts test: timeout-minutes: 15 name: test diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index 7b0ce3f..facd8ed 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -39,6 +39,14 @@ configure { } } } + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } } signing { diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts new file mode 100755 index 0000000..729e6f2 --- /dev/null +++ b/scripts/upload-artifacts @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# ANSI Color Codes +GREEN='\033[32m' +RED='\033[31m' +NC='\033[0m' # No Color + +log_error() { + local msg="$1" + local headers="$2" + local body="$3" + echo -e "${RED}${msg}${NC}" + [[ -f "$headers" ]] && echo -e "${RED}Headers:$(cat "$headers")${NC}" + echo -e "${RED}Body: ${body}${NC}" + exit 1 +} + +upload_file() { + local file_name="$1" + local tmp_headers + tmp_headers=$(mktemp) + + if [ -f "$file_name" ]; then + echo -e "${GREEN}Processing file: $file_name${NC}" + pkg_file_name="mvn${file_name#./build/local-maven-repo}" + + # Get signed URL for uploading artifact file + signed_url_response=$(curl -X POST -G "$URL" \ + -sS --retry 5 \ + -D "$tmp_headers" \ + --data-urlencode "filename=$pkg_file_name" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + + # Validate JSON and extract URL + if ! signed_url=$(echo "$signed_url_response" | jq -e -r '.url' 2>/dev/null) || [[ "$signed_url" == "null" ]]; then + log_error "Failed to get valid signed URL" "$tmp_headers" "$signed_url_response" + fi + + # Set content-type based on file extension + local extension="${file_name##*.}" + local content_type + case "$extension" in + jar) content_type="application/java-archive" ;; + md5|sha1|sha256|sha512) content_type="text/plain" ;; + module) content_type="application/json" ;; + pom|xml) content_type="application/xml" ;; + *) content_type="application/octet-stream" ;; + esac + + # Upload file + upload_response=$(curl -v -X PUT \ + --retry 5 \ + -D "$tmp_headers" \ + -H "Content-Type: $content_type" \ + --data-binary "@${file_name}" "$signed_url" 2>&1) + + if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then + log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + fi + + # Insert small throttle to reduce rate limiting risk + sleep 0.1 + fi +} + +walk_tree() { + local current_dir="$1" + + for entry in "$current_dir"/*; do + # Check that entry is valid + [ -e "$entry" ] || [ -h "$entry" ] || continue + + if [ -d "$entry" ]; then + walk_tree "$entry" + else + upload_file "$entry" + fi + done +} + +cd "$(dirname "$0")/.." + +echo "::group::Creating local Maven content" +./gradlew publishMavenPublicationToLocalFileSystemRepository -PpublishLocal +echo "::endgroup::" + +echo "::group::Uploading to pkg.stainless.com" +walk_tree "./build/local-maven-repo" +echo "::endgroup::" + +echo "::group::Generating instructions" +echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +echo "::endgroup::" From 48c5e957670da44113f9272175a018293fdcdf89 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 08:14:43 +0000 Subject: [PATCH 058/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2aca35a..4208b5c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.0" + ".": "0.6.0" } \ No newline at end of file diff --git a/README.md b/README.md index 472741e..c1e061d 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.5.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.5.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.5.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.6.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.6.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.0) @@ -22,7 +22,7 @@ Use the Stagehand MCP Server to enable AI assistants to interact with this API, -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.5.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.0). @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.5.0") +implementation("com.browserbase.api:stagehand-java:0.6.0") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.browserbase.api:stagehand-java:0.5.0") com.browserbase.api stagehand-java - 0.5.0 + 0.6.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 0db3fe0..4036935 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.5.0" // x-release-please-version + version = "0.6.0" // x-release-please-version } subprojects { From c24726c3c77216cdfdf9605bf89158d1662a59ad Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 08:29:38 +0000 Subject: [PATCH 059/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 4208b5c..ac03171 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.6.0" + ".": "0.6.1" } \ No newline at end of file diff --git a/README.md b/README.md index c1e061d..74eb813 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.6.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.6.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.6.1) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.6.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.1) @@ -22,7 +22,7 @@ Use the Stagehand MCP Server to enable AI assistants to interact with this API, -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.1). @@ -33,7 +33,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.6.0") +implementation("com.browserbase.api:stagehand-java:0.6.1") ``` ### Maven @@ -42,7 +42,7 @@ implementation("com.browserbase.api:stagehand-java:0.6.0") com.browserbase.api stagehand-java - 0.6.0 + 0.6.1 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 4036935..7c2c0c2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.6.0" // x-release-please-version + version = "0.6.1" // x-release-please-version } subprojects { From 23f3d79a738fe2f0718273effd3b2aa174411632 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:18:42 +0000 Subject: [PATCH 060/164] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index a03dd75..3467380 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-419940ce988c43313660d30a5bb5b5c2d89b3b19a0f80fe050331e0f4e8c58d2.yml -openapi_spec_hash: a621ca69697ebba7286cbf9e475c46ad -config_hash: 74111faa0876db6b053526281c444498 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8210daebb6c6b76559ae5c0ca4c0a9189f444da8afb5db1a544395a66ae14a2f.yml +openapi_spec_hash: 2255c1c27382b4227754d64d85258a82 +config_hash: 46336540a7b06c89308171858ad8238c From 6941f3db00cb968d81fdae38cf876e29caac04a4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:54:24 +0000 Subject: [PATCH 061/164] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3467380..cb872bb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8210daebb6c6b76559ae5c0ca4c0a9189f444da8afb5db1a544395a66ae14a2f.yml -openapi_spec_hash: 2255c1c27382b4227754d64d85258a82 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml +openapi_spec_hash: 303329893ced56b2c129fb9fd666144e config_hash: 46336540a7b06c89308171858ad8238c From 5ac37afbb3ea7a0bdb9a3934b3d0395a7abfe62b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:08:57 +0000 Subject: [PATCH 062/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index cb872bb..9affb56 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 46336540a7b06c89308171858ad8238c +config_hash: 6638c79b9a4c739a7f1154eb16321d48 From 766f2e478c90c8555e3b10014a4a706c87b7c795 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:09:30 +0000 Subject: [PATCH 063/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 9affb56..d6bcc31 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 6638c79b9a4c739a7f1154eb16321d48 +config_hash: 1bbded545069024fcb805e1f6c6a9985 From 129d69f4312c47e2808d1be59651886a6e8f35cf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:04:51 +0000 Subject: [PATCH 064/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index d6bcc31..156799b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 1bbded545069024fcb805e1f6c6a9985 +config_hash: 2357dc3b80abe40de8d2dc4885928306 From 4a009cd0c8ecb83e1f2606b6722dda8a4784bfba Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 23:44:04 +0000 Subject: [PATCH 065/164] feat(api): manual updates --- .stats.yml | 2 +- LICENSE | 202 +----------------- .../main/kotlin/stagehand.publish.gradle.kts | 2 +- 3 files changed, 6 insertions(+), 200 deletions(-) diff --git a/.stats.yml b/.stats.yml index 156799b..01457a6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 2357dc3b80abe40de8d2dc4885928306 +config_hash: 3f1eb6ae44a4987a7c0c8a9d95035975 diff --git a/LICENSE b/LICENSE index d15d021..a7b82c2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,7 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +Copyright 2026 stagehand - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - 1. Definitions. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2026 Stagehand - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index facd8ed..f424b58 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -15,7 +15,7 @@ configure { licenses { license { - name.set("Apache-2.0") + name.set("MIT") } } From e601049ed81582679046bed53d987be4a6d32ed0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:10:12 +0000 Subject: [PATCH 066/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 01457a6..2f45fa4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 3f1eb6ae44a4987a7c0c8a9d95035975 +config_hash: 0e6aecd610184fc5d011e30698df9a56 From 1e3acb8cfeeff74931c2828cc566d432efa8fc25 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:13:52 +0000 Subject: [PATCH 067/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2f45fa4..7650758 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 0e6aecd610184fc5d011e30698df9a56 +config_hash: 3906b0eb870b3efb11f24b0069668c94 From 600ca5433c1753287b33721d2b49dc272c50e796 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:15:52 +0000 Subject: [PATCH 068/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 7650758..f4e4a76 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 3906b0eb870b3efb11f24b0069668c94 +config_hash: 3ad8653f1cf35720ac8f2f8643969e15 From 17ed117b7cb15f9674cfa839fc0ea86b57b6849c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:17:43 +0000 Subject: [PATCH 069/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index f4e4a76..936a1e9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: 3ad8653f1cf35720ac8f2f8643969e15 +config_hash: d2eff937029f6230c90a974d0b64e024 From 8ff31a96575268babd677f04cf8a5e6cb0184c31 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:19:29 +0000 Subject: [PATCH 070/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 936a1e9..fbdd509 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: d2eff937029f6230c90a974d0b64e024 +config_hash: dbb44d668902bdea601850a0db94302b From 79c866962452afb8e46be80bf31068b266c92e9d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:30:48 +0000 Subject: [PATCH 071/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index fbdd509..8a75e9b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: dbb44d668902bdea601850a0db94302b +config_hash: e8739aa4b8fb23a89fbf1f3b1ba2a52f From 6b7443e7fb771ea7d9327f7f3721bf598b74833c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:37:01 +0000 Subject: [PATCH 072/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 8a75e9b..ee5126e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml openapi_spec_hash: 303329893ced56b2c129fb9fd666144e -config_hash: e8739aa4b8fb23a89fbf1f3b1ba2a52f +config_hash: d4df55e4b30aac2d8d0982be97f837c4 From d2ee7e4080e5044993ffc24656286c887c1f7257 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 00:02:29 +0000 Subject: [PATCH 073/164] feat: x-stainless-any fix, optional frame id, ModelConfigString fix --- .stats.yml | 4 +- .../api/models/sessions/ModelConfig.kt | 59 +++++++++++-------- .../api/models/sessions/SessionActParams.kt | 45 ++++++-------- .../api/models/sessions/SessionEndParams.kt | 21 +------ .../models/sessions/SessionExecuteParams.kt | 45 ++++++-------- .../models/sessions/SessionExtractParams.kt | 45 ++++++-------- .../models/sessions/SessionNavigateParams.kt | 31 ++++------ .../models/sessions/SessionObserveParams.kt | 45 ++++++-------- .../api/models/sessions/SessionStartParams.kt | 38 +++++------- .../api/models/sessions/ModelConfigTest.kt | 18 +++--- .../models/sessions/SessionActParamsTest.kt | 20 ++----- .../models/sessions/SessionEndParamsTest.kt | 12 +--- .../sessions/SessionExecuteParamsTest.kt | 20 ++----- .../sessions/SessionExtractParamsTest.kt | 20 ++----- .../sessions/SessionNavigateParamsTest.kt | 12 +--- .../sessions/SessionObserveParamsTest.kt | 20 ++----- .../models/sessions/SessionStartParamsTest.kt | 12 +--- .../api/services/ErrorHandlingTest.kt | 18 ------ .../api/services/ServiceParamsTest.kt | 5 +- .../services/async/SessionServiceAsyncTest.kt | 28 +++------ .../services/blocking/SessionServiceTest.kt | 28 +++------ .../api/proguard/ProGuardCompatibilityTest.kt | 2 +- 22 files changed, 185 insertions(+), 363 deletions(-) diff --git a/.stats.yml b/.stats.yml index ee5126e..ee1de31 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-991d1530002115ecec027f98cad357d39ca1ece6784f62d48e6740b8830e1104.yml -openapi_spec_hash: 303329893ced56b2c129fb9fd666144e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-07032b695bc66ecd76328d936b41e01cfad508a870928c09c185f5faa5ea66ab.yml +openapi_spec_hash: fca4b895ce36ad547fb015c3dd38821f config_hash: d4df55e4b30aac2d8d0982be97f837c4 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index ce0785b..f8467e9 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -30,34 +30,35 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' (e.g., + * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') */ @JsonDeserialize(using = ModelConfig.Deserializer::class) @JsonSerialize(using = ModelConfig.Serializer::class) class ModelConfig private constructor( - private val name: String? = null, + private val string: String? = null, private val modelConfigObject: ModelConfigObject? = null, private val _json: JsonValue? = null, ) { /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' (e.g., + * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') */ - fun name(): Optional = Optional.ofNullable(name) + fun string(): Optional = Optional.ofNullable(string) fun modelConfigObject(): Optional = Optional.ofNullable(modelConfigObject) - fun isName(): Boolean = name != null + fun isString(): Boolean = string != null fun isModelConfigObject(): Boolean = modelConfigObject != null /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' (e.g., + * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') */ - fun asName(): String = name.getOrThrow("name") + fun asString(): String = string.getOrThrow("string") fun asModelConfigObject(): ModelConfigObject = modelConfigObject.getOrThrow("modelConfigObject") @@ -65,7 +66,7 @@ private constructor( fun accept(visitor: Visitor): T = when { - name != null -> visitor.visitName(name) + string != null -> visitor.visitString(string) modelConfigObject != null -> visitor.visitModelConfigObject(modelConfigObject) else -> visitor.unknown(_json) } @@ -79,7 +80,7 @@ private constructor( accept( object : Visitor { - override fun visitName(name: String) {} + override fun visitString(string: String) {} override fun visitModelConfigObject(modelConfigObject: ModelConfigObject) { modelConfigObject.validate() @@ -106,7 +107,7 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitName(name: String) = 1 + override fun visitString(string: String) = 1 override fun visitModelConfigObject(modelConfigObject: ModelConfigObject) = modelConfigObject.validity() @@ -121,15 +122,15 @@ private constructor( } return other is ModelConfig && - name == other.name && + string == other.string && modelConfigObject == other.modelConfigObject } - override fun hashCode(): Int = Objects.hash(name, modelConfigObject) + override fun hashCode(): Int = Objects.hash(string, modelConfigObject) override fun toString(): String = when { - name != null -> "ModelConfig{name=$name}" + string != null -> "ModelConfig{string=$string}" modelConfigObject != null -> "ModelConfig{modelConfigObject=$modelConfigObject}" _json != null -> "ModelConfig{_unknown=$_json}" else -> throw IllegalStateException("Invalid ModelConfig") @@ -138,10 +139,11 @@ private constructor( companion object { /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') */ - @JvmStatic fun ofName(name: String) = ModelConfig(name = name) + @JvmStatic fun ofString(string: String) = ModelConfig(string = string) @JvmStatic fun ofModelConfigObject(modelConfigObject: ModelConfigObject) = @@ -154,10 +156,11 @@ private constructor( interface Visitor { /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') */ - fun visitName(name: String): T + fun visitString(string: String): T fun visitModelConfigObject(modelConfigObject: ModelConfigObject): T @@ -186,7 +189,7 @@ private constructor( ModelConfig(modelConfigObject = it, _json = json) }, tryDeserialize(node, jacksonTypeRef())?.let { - ModelConfig(name = it, _json = json) + ModelConfig(string = it, _json = json) }, ) .filterNotNull() @@ -212,7 +215,7 @@ private constructor( provider: SerializerProvider, ) { when { - value.name != null -> generator.writeObject(value.name) + value.string != null -> generator.writeObject(value.string) value.modelConfigObject != null -> generator.writeObject(value.modelConfigObject) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid ModelConfig") @@ -243,7 +246,9 @@ private constructor( ) : this(modelName, apiKey, baseUrl, provider, mutableMapOf()) /** - * Model name string (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -345,7 +350,11 @@ private constructor( additionalProperties = modelConfigObject.additionalProperties.toMutableMap() } - /** Model name string (e.g., 'openai/gpt-5-nano', 'anthropic/claude-4.5-opus') */ + /** + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') + */ fun modelName(modelName: String) = modelName(JsonField.of(modelName)) /** diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 182931c..92df30c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -28,8 +28,6 @@ import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -39,7 +37,6 @@ import kotlin.jvm.optionals.getOrNull class SessionActParams private constructor( private val id: String?, - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, @@ -49,9 +46,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) @@ -125,7 +119,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -134,7 +127,6 @@ private constructor( @JvmSynthetic internal fun from(sessionActParams: SessionActParams) = apply { id = sessionActParams.id - xSentAt = sessionActParams.xSentAt xStreamResponse = sessionActParams.xStreamResponse body = sessionActParams.body.toBuilder() additionalHeaders = sessionActParams.additionalHeaders.toBuilder() @@ -147,12 +139,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -191,7 +177,10 @@ private constructor( fun input(action: Action) = apply { body.input(action) } /** Target frame ID for the action */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } + fun frameId(frameId: String?) = apply { body.frameId(frameId) } + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -343,7 +332,6 @@ private constructor( fun build(): SessionActParams = SessionActParams( id, - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -362,7 +350,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -489,7 +476,10 @@ private constructor( fun input(action: Action) = input(Input.ofAction(action)) /** Target frame ID for the action */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + fun frameId(frameId: String?) = frameId(JsonField.ofNullable(frameId)) + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -799,8 +789,9 @@ private constructor( ) : this(model, timeout, variables, mutableMapOf()) /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -881,8 +872,9 @@ private constructor( } /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') */ fun model(model: ModelConfig) = model(JsonField.of(model)) @@ -895,8 +887,8 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ - fun model(name: String) = model(ModelConfig.ofName(name)) + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) /** * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. @@ -1253,7 +1245,6 @@ private constructor( return other is SessionActParams && id == other.id && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -1261,8 +1252,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionActParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionActParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index c861cc2..2114c89 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -15,8 +15,6 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -26,7 +24,6 @@ import kotlin.jvm.optionals.getOrNull class SessionEndParams private constructor( private val id: String?, - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, @@ -36,9 +33,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) @@ -66,7 +60,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -75,7 +68,6 @@ private constructor( @JvmSynthetic internal fun from(sessionEndParams: SessionEndParams) = apply { id = sessionEndParams.id - xSentAt = sessionEndParams.xSentAt xStreamResponse = sessionEndParams.xStreamResponse body = sessionEndParams.body.toBuilder() additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() @@ -88,12 +80,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -239,7 +225,6 @@ private constructor( fun build(): SessionEndParams = SessionEndParams( id, - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -258,7 +243,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -522,7 +506,6 @@ private constructor( return other is SessionEndParams && id == other.id && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -530,8 +513,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionEndParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionEndParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 813b432..65c7508 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -16,8 +16,6 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -27,7 +25,6 @@ import kotlin.jvm.optionals.getOrNull class SessionExecuteParams private constructor( private val id: String?, - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, @@ -37,9 +34,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) @@ -112,7 +106,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -121,7 +114,6 @@ private constructor( @JvmSynthetic internal fun from(sessionExecuteParams: SessionExecuteParams) = apply { id = sessionExecuteParams.id - xSentAt = sessionExecuteParams.xSentAt xStreamResponse = sessionExecuteParams.xStreamResponse body = sessionExecuteParams.body.toBuilder() additionalHeaders = sessionExecuteParams.additionalHeaders.toBuilder() @@ -134,12 +126,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -189,7 +175,10 @@ private constructor( } /** Target frame ID for the agent */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } + fun frameId(frameId: String?) = apply { body.frameId(frameId) } + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -332,7 +321,6 @@ private constructor( fun build(): SessionExecuteParams = SessionExecuteParams( id, - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -351,7 +339,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -495,7 +482,10 @@ private constructor( } /** Target frame ID for the agent */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + fun frameId(frameId: String?) = frameId(JsonField.ofNullable(frameId)) + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -633,8 +623,9 @@ private constructor( fun cua(): Optional = cua.getOptional("cua") /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -737,8 +728,9 @@ private constructor( fun cua(cua: JsonField) = apply { this.cua = cua } /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') */ fun model(model: ModelConfig) = model(JsonField.of(model)) @@ -751,8 +743,8 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ - fun model(name: String) = model(ModelConfig.ofName(name)) + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) /** * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. @@ -1401,7 +1393,6 @@ private constructor( return other is SessionExecuteParams && id == other.id && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -1409,8 +1400,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionExecuteParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionExecuteParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 3ef55df..45507fe 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -16,8 +16,6 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -27,7 +25,6 @@ import kotlin.jvm.optionals.getOrNull class SessionExtractParams private constructor( private val id: String?, - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, @@ -37,9 +34,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) @@ -123,7 +117,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -132,7 +125,6 @@ private constructor( @JvmSynthetic internal fun from(sessionExtractParams: SessionExtractParams) = apply { id = sessionExtractParams.id - xSentAt = sessionExtractParams.xSentAt xStreamResponse = sessionExtractParams.xStreamResponse body = sessionExtractParams.body.toBuilder() additionalHeaders = sessionExtractParams.additionalHeaders.toBuilder() @@ -145,12 +137,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -173,7 +159,10 @@ private constructor( fun body(body: Body) = apply { this.body = body.toBuilder() } /** Target frame ID for the extraction */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } + fun frameId(frameId: String?) = apply { body.frameId(frameId) } + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -341,7 +330,6 @@ private constructor( fun build(): SessionExtractParams = SessionExtractParams( id, - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -360,7 +348,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -485,7 +472,10 @@ private constructor( } /** Target frame ID for the extraction */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + fun frameId(frameId: String?) = frameId(JsonField.ofNullable(frameId)) + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -638,8 +628,9 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -718,8 +709,9 @@ private constructor( } /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') */ fun model(model: ModelConfig) = model(JsonField.of(model)) @@ -732,8 +724,8 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ - fun model(name: String) = model(ModelConfig.ofName(name)) + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) /** * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. @@ -1087,7 +1079,6 @@ private constructor( return other is SessionExtractParams && id == other.id && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -1095,8 +1086,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionExtractParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionExtractParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index 2d63849..d848600 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -16,8 +16,6 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -27,7 +25,6 @@ import kotlin.jvm.optionals.getOrNull class SessionNavigateParams private constructor( private val id: String?, - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, @@ -37,9 +34,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) @@ -128,7 +122,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -137,7 +130,6 @@ private constructor( @JvmSynthetic internal fun from(sessionNavigateParams: SessionNavigateParams) = apply { id = sessionNavigateParams.id - xSentAt = sessionNavigateParams.xSentAt xStreamResponse = sessionNavigateParams.xStreamResponse body = sessionNavigateParams.body.toBuilder() additionalHeaders = sessionNavigateParams.additionalHeaders.toBuilder() @@ -150,12 +142,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -189,7 +175,10 @@ private constructor( fun url(url: JsonField) = apply { body.url(url) } /** Target frame ID for the navigation */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } + fun frameId(frameId: String?) = apply { body.frameId(frameId) } + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -355,7 +344,6 @@ private constructor( fun build(): SessionNavigateParams = SessionNavigateParams( id, - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -374,7 +362,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -519,7 +506,10 @@ private constructor( fun url(url: JsonField) = apply { this.url = url } /** Target frame ID for the navigation */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + fun frameId(frameId: String?) = frameId(JsonField.ofNullable(frameId)) + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -1150,7 +1140,6 @@ private constructor( return other is SessionNavigateParams && id == other.id && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -1158,8 +1147,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionNavigateParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionNavigateParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 37efafd..4ba5e2f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -15,8 +15,6 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -28,7 +26,6 @@ import kotlin.jvm.optionals.getOrNull class SessionObserveParams private constructor( private val id: String?, - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, @@ -38,9 +35,6 @@ private constructor( /** Unique session identifier */ fun id(): Optional = Optional.ofNullable(id) - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) @@ -109,7 +103,6 @@ private constructor( class Builder internal constructor() { private var id: String? = null - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -118,7 +111,6 @@ private constructor( @JvmSynthetic internal fun from(sessionObserveParams: SessionObserveParams) = apply { id = sessionObserveParams.id - xSentAt = sessionObserveParams.xSentAt xStreamResponse = sessionObserveParams.xStreamResponse body = sessionObserveParams.body.toBuilder() additionalHeaders = sessionObserveParams.additionalHeaders.toBuilder() @@ -131,12 +123,6 @@ private constructor( /** Alias for calling [Builder.id] with `id.orElse(null)`. */ fun id(id: Optional) = id(id.getOrNull()) - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -158,7 +144,10 @@ private constructor( fun body(body: Body) = apply { this.body = body.toBuilder() } /** Target frame ID for the observation */ - fun frameId(frameId: String) = apply { body.frameId(frameId) } + fun frameId(frameId: String?) = apply { body.frameId(frameId) } + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -315,7 +304,6 @@ private constructor( fun build(): SessionObserveParams = SessionObserveParams( id, - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -334,7 +322,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -440,7 +427,10 @@ private constructor( } /** Target frame ID for the observation */ - fun frameId(frameId: String) = frameId(JsonField.of(frameId)) + fun frameId(frameId: String?) = frameId(JsonField.ofNullable(frameId)) + + /** Alias for calling [Builder.frameId] with `frameId.orElse(null)`. */ + fun frameId(frameId: Optional) = frameId(frameId.getOrNull()) /** * Sets [Builder.frameId] to an arbitrary JSON value. @@ -578,8 +568,9 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -658,8 +649,9 @@ private constructor( } /** - * Model name string with provider prefix (e.g., 'openai/gpt-5-nano', - * 'anthropic/claude-4.5-opus') + * Model name string with provider prefix. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') */ fun model(model: ModelConfig) = model(JsonField.of(model)) @@ -672,8 +664,8 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofName(name)`. */ - fun model(name: String) = model(ModelConfig.ofName(name)) + /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ + fun model(string: String) = model(ModelConfig.ofString(string)) /** * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. @@ -927,7 +919,6 @@ private constructor( return other is SessionObserveParams && id == other.id && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -935,8 +926,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(id, xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionObserveParams{id=$id, xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionObserveParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 2d3ece2..85b3c01 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -29,8 +29,6 @@ import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import java.time.OffsetDateTime -import java.time.format.DateTimeFormatter import java.util.Collections import java.util.Objects import java.util.Optional @@ -42,21 +40,18 @@ import kotlin.jvm.optionals.getOrNull */ class SessionStartParams private constructor( - private val xSentAt: OffsetDateTime?, private val xStreamResponse: XStreamResponse?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - /** ISO timestamp when request was sent */ - fun xSentAt(): Optional = Optional.ofNullable(xSentAt) - /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) /** - * Model name to use for AI operations + * Model name to use for AI operations. Always use the format 'provider/model-name' (e.g., + * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -246,7 +241,6 @@ private constructor( /** A builder for [SessionStartParams]. */ class Builder internal constructor() { - private var xSentAt: OffsetDateTime? = null private var xStreamResponse: XStreamResponse? = null private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() @@ -254,19 +248,12 @@ private constructor( @JvmSynthetic internal fun from(sessionStartParams: SessionStartParams) = apply { - xSentAt = sessionStartParams.xSentAt xStreamResponse = sessionStartParams.xStreamResponse body = sessionStartParams.body.toBuilder() additionalHeaders = sessionStartParams.additionalHeaders.toBuilder() additionalQueryParams = sessionStartParams.additionalQueryParams.toBuilder() } - /** ISO timestamp when request was sent */ - fun xSentAt(xSentAt: OffsetDateTime?) = apply { this.xSentAt = xSentAt } - - /** Alias for calling [Builder.xSentAt] with `xSentAt.orElse(null)`. */ - fun xSentAt(xSentAt: Optional) = xSentAt(xSentAt.getOrNull()) - /** Whether to stream the response via SSE */ fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { this.xStreamResponse = xStreamResponse @@ -290,7 +277,10 @@ private constructor( */ fun body(body: Body) = apply { this.body = body.toBuilder() } - /** Model name to use for AI operations */ + /** + * Model name to use for AI operations. Always use the format 'provider/model-name' (e.g., + * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') + */ fun modelName(modelName: String) = apply { body.modelName(modelName) } /** @@ -570,7 +560,6 @@ private constructor( */ fun build(): SessionStartParams = SessionStartParams( - xSentAt, xStreamResponse, body.build(), additionalHeaders.build(), @@ -583,7 +572,6 @@ private constructor( override fun _headers(): Headers = Headers.builder() .apply { - xSentAt?.let { put("x-sent-at", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(it)) } xStreamResponse?.let { put("x-stream-response", it.toString()) } putAll(additionalHeaders) } @@ -656,7 +644,8 @@ private constructor( ) /** - * Model name to use for AI operations + * Model name to use for AI operations. Always use the format 'provider/model-name' (e.g., + * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -898,7 +887,11 @@ private constructor( additionalProperties = body.additionalProperties.toMutableMap() } - /** Model name to use for AI operations */ + /** + * Model name to use for AI operations. Always use the format 'provider/model-name' + * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', + * 'google/gemini-2.0-flash') + */ fun modelName(modelName: String) = modelName(JsonField.of(modelName)) /** @@ -7300,7 +7293,6 @@ private constructor( } return other is SessionStartParams && - xSentAt == other.xSentAt && xStreamResponse == other.xStreamResponse && body == other.body && additionalHeaders == other.additionalHeaders && @@ -7308,8 +7300,8 @@ private constructor( } override fun hashCode(): Int = - Objects.hash(xSentAt, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash(xStreamResponse, body, additionalHeaders, additionalQueryParams) override fun toString() = - "SessionStartParams{xSentAt=$xSentAt, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionStartParams{xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index db47f8d..0190f8e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -13,19 +13,19 @@ import org.junit.jupiter.api.assertThrows internal class ModelConfigTest { @Test - fun ofName() { - val name = "openai/gpt-5-nano" + fun ofString() { + val string = "openai/gpt-4o" - val modelConfig = ModelConfig.ofName(name) + val modelConfig = ModelConfig.ofString(string) - assertThat(modelConfig.name()).contains(name) + assertThat(modelConfig.string()).contains(string) assertThat(modelConfig.modelConfigObject()).isEmpty } @Test - fun ofNameRoundtrip() { + fun ofStringRoundtrip() { val jsonMapper = jsonMapper() - val modelConfig = ModelConfig.ofName("openai/gpt-5-nano") + val modelConfig = ModelConfig.ofString("openai/gpt-4o") val roundtrippedModelConfig = jsonMapper.readValue( @@ -40,7 +40,7 @@ internal class ModelConfigTest { fun ofModelConfigObject() { val modelConfigObject = ModelConfig.ModelConfigObject.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-4o") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) @@ -48,7 +48,7 @@ internal class ModelConfigTest { val modelConfig = ModelConfig.ofModelConfigObject(modelConfigObject) - assertThat(modelConfig.name()).isEmpty + assertThat(modelConfig.string()).isEmpty assertThat(modelConfig.modelConfigObject()).contains(modelConfigObject) } @@ -58,7 +58,7 @@ internal class ModelConfigTest { val modelConfig = ModelConfig.ofModelConfigObject( ModelConfig.ModelConfigObject.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-4o") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 54acc4f..aec22f7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -4,7 +4,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -14,13 +13,12 @@ internal class SessionActParamsTest { fun create() { SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -50,13 +48,12 @@ internal class SessionActParamsTest { val params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -69,13 +66,7 @@ internal class SessionActParamsTest { val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -96,13 +87,12 @@ internal class SessionActParamsTest { val params = SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -121,7 +111,7 @@ internal class SessionActParamsTest { assertThat(body.options()) .contains( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 9081b87..5d789fc 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -4,7 +4,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -14,7 +13,6 @@ internal class SessionEndParamsTest { fun create() { SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) .build() @@ -34,20 +32,13 @@ internal class SessionEndParamsTest { val params = SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) .build() val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -64,7 +55,6 @@ internal class SessionEndParamsTest { val params = SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 2064b33..6b36c20 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -3,7 +3,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -13,12 +12,11 @@ internal class SessionExecuteParamsTest { fun create() { SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -61,12 +59,11 @@ internal class SessionExecuteParamsTest { val params = SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -85,13 +82,7 @@ internal class SessionExecuteParamsTest { val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -119,12 +110,11 @@ internal class SessionExecuteParamsTest { val params = SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -147,7 +137,7 @@ internal class SessionExecuteParamsTest { .isEqualTo( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 54b80a6..1ee8821 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -4,7 +4,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -14,13 +13,12 @@ internal class SessionExtractParamsTest { fun create() { SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -48,13 +46,12 @@ internal class SessionExtractParamsTest { val params = SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -68,13 +65,7 @@ internal class SessionExtractParamsTest { val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -92,13 +83,12 @@ internal class SessionExtractParamsTest { val params = SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -118,7 +108,7 @@ internal class SessionExtractParamsTest { assertThat(body.options()) .contains( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt index 3616da2..3e48bb2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionNavigateParamsTest.kt @@ -3,7 +3,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -13,7 +12,6 @@ internal class SessionNavigateParamsTest { fun create() { SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -46,7 +44,6 @@ internal class SessionNavigateParamsTest { val params = SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -62,13 +59,7 @@ internal class SessionNavigateParamsTest { val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -89,7 +80,6 @@ internal class SessionNavigateParamsTest { val params = SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index eeb111b..28cfb46 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -3,7 +3,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -13,13 +12,12 @@ internal class SessionObserveParamsTest { fun create() { SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -42,13 +40,12 @@ internal class SessionObserveParamsTest { val params = SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -57,13 +54,7 @@ internal class SessionObserveParamsTest { val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -81,13 +72,12 @@ internal class SessionObserveParamsTest { val params = SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -101,7 +91,7 @@ internal class SessionObserveParamsTest { assertThat(body.options()) .contains( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 4e4e0dc..d3cd55c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -4,7 +4,6 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -13,7 +12,6 @@ internal class SessionStartParamsTest { @Test fun create() { SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -159,7 +157,6 @@ internal class SessionStartParamsTest { fun headers() { val params = SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -306,13 +303,7 @@ internal class SessionStartParamsTest { val headers = params._headers() - assertThat(headers) - .isEqualTo( - Headers.builder() - .put("x-sent-at", "2025-01-15T10:30:00Z") - .put("x-stream-response", "true") - .build() - ) + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) } @Test @@ -328,7 +319,6 @@ internal class SessionStartParamsTest { fun body() { val params = SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 6dab5ba..8f3f827 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -23,7 +23,6 @@ import com.github.tomakehurst.wiremock.client.WireMock.status import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.entry import org.junit.jupiter.api.BeforeEach @@ -75,7 +74,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -252,7 +250,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -429,7 +426,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -606,7 +602,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -783,7 +778,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -960,7 +954,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -1137,7 +1130,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -1314,7 +1306,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -1491,7 +1482,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -1668,7 +1658,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -1845,7 +1834,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -2022,7 +2010,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -2199,7 +2186,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -2376,7 +2362,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -2553,7 +2538,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -2730,7 +2714,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -2905,7 +2888,6 @@ internal class ErrorHandlingTest { assertThrows { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 33f0206..b01ce5f 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -17,7 +17,6 @@ import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.client.WireMock.verify import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest -import java.time.OffsetDateTime import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -48,7 +47,6 @@ internal class ServiceParamsTest { sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) @@ -214,13 +212,12 @@ internal class ServiceParamsTest { sessionService.act( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index d457ad4..bd4953d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -12,7 +12,6 @@ import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams -import java.time.OffsetDateTime import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -36,13 +35,12 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.act( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -74,13 +72,12 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.actStreaming( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -113,7 +110,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.end( SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) .build() @@ -139,12 +135,11 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.execute( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -182,12 +177,11 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.executeStreaming( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -226,13 +220,12 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.extract( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -265,13 +258,12 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.extractStreaming( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -305,7 +297,6 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.navigate( SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -340,13 +331,12 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.observe( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -374,13 +364,12 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.observeStreaming( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -408,7 +397,6 @@ internal class SessionServiceAsyncTest { val responseFuture = sessionServiceAsync.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index b7d0e6b..41e40f0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -12,7 +12,6 @@ import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionStartParams -import java.time.OffsetDateTime import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -36,13 +35,12 @@ internal class SessionServiceTest { sessionService.act( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -73,13 +71,12 @@ internal class SessionServiceTest { sessionService.actStreaming( SessionActParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionActParams.XStreamResponse.TRUE) .input("Click the login button") .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -112,7 +109,6 @@ internal class SessionServiceTest { sessionService.end( SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) ._forceBody(JsonValue.from(mapOf())) .build() @@ -137,12 +133,11 @@ internal class SessionServiceTest { sessionService.execute( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -179,12 +174,11 @@ internal class SessionServiceTest { sessionService.executeStreaming( SessionExecuteParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExecuteParams.XStreamResponse.TRUE) .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -223,13 +217,12 @@ internal class SessionServiceTest { sessionService.extract( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -261,13 +254,12 @@ internal class SessionServiceTest { sessionService.extractStreaming( SessionExtractParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionExtractParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("#main-content") .timeout(30000.0) .build() @@ -301,7 +293,6 @@ internal class SessionServiceTest { sessionService.navigate( SessionNavigateParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionNavigateParams.XStreamResponse.TRUE) .url("https://example.com") .frameId("frameId") @@ -335,13 +326,12 @@ internal class SessionServiceTest { sessionService.observe( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -368,13 +358,12 @@ internal class SessionServiceTest { sessionService.observeStreaming( SessionObserveParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionObserveParams.XStreamResponse.TRUE) .frameId("frameId") .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-5-nano") + .model("openai/gpt-4o") .selector("nav") .timeout(30000.0) .build() @@ -402,7 +391,6 @@ internal class SessionServiceTest { val response = sessionService.start( SessionStartParams.builder() - .xSentAt(OffsetDateTime.parse("2025-01-15T10:30:00Z")) .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) .modelName("openai/gpt-4o") .actTimeoutMs(0.0) diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index f3e08fa..7db4e74 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -77,7 +77,7 @@ internal class ProGuardCompatibilityTest { @Test fun modelConfigRoundtrip() { val jsonMapper = jsonMapper() - val modelConfig = ModelConfig.ofName("openai/gpt-5-nano") + val modelConfig = ModelConfig.ofString("openai/gpt-4o") val roundtrippedModelConfig = jsonMapper.readValue( From 05c10a3a24bda88b82ca658bdb820232183fb539 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 00:42:08 +0000 Subject: [PATCH 074/164] feat(api): manual updates --- .github/workflows/publish-sonatype.yml | 2 +- .stats.yml | 2 +- README.md | 2 + build.gradle.kts | 13 --- buildSrc/build.gradle.kts | 3 + .../src/main/kotlin/stagehand.java.gradle.kts | 9 -- .../main/kotlin/stagehand.publish.gradle.kts | 105 +++++++++--------- 7 files changed, 61 insertions(+), 75 deletions(-) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 6a27d98..67e28c7 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -33,7 +33,7 @@ jobs: 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 publish --no-configuration-cache + ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache env: SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index ee1de31..71adca4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-07032b695bc66ecd76328d936b41e01cfad508a870928c09c185f5faa5ea66ab.yml openapi_spec_hash: fca4b895ce36ad547fb015c3dd38821f -config_hash: d4df55e4b30aac2d8d0982be97f837c4 +config_hash: bf22187c626f0401180a332e3f3f6d8c diff --git a/README.md b/README.md index 74eb813..ee11525 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://docs.stagehand.dev) from applications written in Java. +The Stagehand Java SDK is similar to the Stagehand Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. + It is generated with [Stainless](https://www.stainless.com/). ## MCP Server diff --git a/build.gradle.kts b/build.gradle.kts index 7c2c0c2..49dfc3e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,4 @@ plugins { - id("io.github.gradle-nexus.publish-plugin") version "1.1.0" id("org.jetbrains.dokka") version "2.0.0" } @@ -35,15 +34,3 @@ tasks.named("dokkaJavadocCollector").configure { .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } - -nexusPublishing { - repositories { - sonatype { - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) - - username.set(System.getenv("SONATYPE_USERNAME")) - password.set(System.getenv("SONATYPE_PASSWORD")) - } - } -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0b14135..c6dc92e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,12 +1,15 @@ plugins { `kotlin-dsl` kotlin("jvm") version "1.9.20" + id("com.vanniktech.maven.publish") version "0.28.0" } repositories { gradlePluginPortal() + mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") + implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0") } diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts index 81d5d32..70fc33f 100644 --- a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -8,11 +8,6 @@ repositories { mavenCentral() } -configure { - withJavadocJar() - withSourcesJar() -} - java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) @@ -27,10 +22,6 @@ tasks.withType().configureEach { options.release.set(8) } -tasks.named("javadocJar") { - setZip64(true) -} - tasks.named("jar") { manifest { attributes(mapOf( diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index f424b58..f45a9d7 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -1,68 +1,71 @@ +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinJvm +import com.vanniktech.maven.publish.MavenPublishBaseExtension +import com.vanniktech.maven.publish.SonatypeHost + plugins { - `maven-publish` - signing + id("com.vanniktech.maven.publish") +} + +publishing { + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } } -configure { - publications { - register("maven") { - from(components["java"]) +repositories { + gradlePluginPortal() + mavenCentral() +} - pom { - name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") - url.set("https://docs.stagehand.dev") +extra["signingInMemoryKey"] = System.getenv("GPG_SIGNING_KEY") +extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") +extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") - licenses { - license { - name.set("MIT") - } - } +configure { + if (!project.hasProperty("publishLocal")) { + signAllPublications() + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + } - developers { - developer { - name.set("Stagehand") - } - } + coordinates(project.group.toString(), project.name, project.version.toString()) + configure( + KotlinJvm( + javadocJar = JavadocJar.Dokka("dokkaJavadoc"), + sourcesJar = true, + ) + ) - scm { - connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - url.set("https://github.com/browserbase/stagehand-java") - } + pom { + name.set("Stagehand API") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + url.set("https://docs.stagehand.dev") - versionMapping { - allVariants { - fromResolutionResult() - } - } + licenses { + license { + name.set("MIT") } } - } - repositories { - if (project.hasProperty("publishLocal")) { - maven { - name = "LocalFileSystem" - url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + + developers { + developer { + name.set("Stagehand") } } - } -} -signing { - val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null } - val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null } - val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null } - if (signingKey != null && signingPassword != null) { - useInMemoryPgpKeys( - signingKeyId, - signingKey, - signingPassword, - ) - sign(publishing.publications["maven"]) + scm { + connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + url.set("https://github.com/browserbase/stagehand-java") + } } } -tasks.named("publish") { - dependsOn(":closeAndReleaseSonatypeStagingRepository") +tasks.withType().configureEach { + isZip64 = true } From 9babd8951451e41270ee4a89fa4276695f94c89e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 04:11:29 +0000 Subject: [PATCH 075/164] chore(internal): clean up maven repo artifact script and add html documentation to repo root --- scripts/upload-artifacts | 44 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index 729e6f2..df0c8d9 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -7,6 +7,8 @@ GREEN='\033[32m' RED='\033[31m' NC='\033[0m' # No Color +MAVEN_REPO_PATH="./build/local-maven-repo" + log_error() { local msg="$1" local headers="$2" @@ -24,7 +26,7 @@ upload_file() { if [ -f "$file_name" ]; then echo -e "${GREEN}Processing file: $file_name${NC}" - pkg_file_name="mvn${file_name#./build/local-maven-repo}" + pkg_file_name="mvn${file_name#"${MAVEN_REPO_PATH}"}" # Get signed URL for uploading artifact file signed_url_response=$(curl -X POST -G "$URL" \ @@ -47,6 +49,7 @@ upload_file() { md5|sha1|sha256|sha512) content_type="text/plain" ;; module) content_type="application/json" ;; pom|xml) content_type="application/xml" ;; + html) content_type="text/html" ;; *) content_type="application/octet-stream" ;; esac @@ -81,6 +84,41 @@ walk_tree() { done } +generate_instructions() { + cat << EOF > "$MAVEN_REPO_PATH/index.html" + + + + Maven Repo + + +

Stainless SDK Maven Repository

+

This is the Maven repository for your Stainless Java SDK build.

+ +

Directions

+

To use the uploaded Maven repository, add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

If you're using Gradle, add the following to your build.gradle file:

+
repositories {
+    maven {
+        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+    }
+}
+ + +EOF + upload_file "${MAVEN_REPO_PATH}/index.html" + + echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" + echo "For more details, see the directions in https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn/index.html" +} + cd "$(dirname "$0")/.." echo "::group::Creating local Maven content" @@ -88,9 +126,9 @@ echo "::group::Creating local Maven content" echo "::endgroup::" echo "::group::Uploading to pkg.stainless.com" -walk_tree "./build/local-maven-repo" +walk_tree "$MAVEN_REPO_PATH" echo "::endgroup::" echo "::group::Generating instructions" -echo "Configure maven or gradle to use the repo located at 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'" +generate_instructions echo "::endgroup::" From 8e6eef03e964da89f7726a8c4e17cb29b8d2a104 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:21:58 +0000 Subject: [PATCH 076/164] chore: test on Jackson 2.14.0 to avoid encountering FasterXML/jackson-databind#3240 in tests fix: date time deserialization leniency --- README.md | 2 ++ stagehand-java-core/build.gradle.kts | 18 +++++----- .../com/browserbase/api/core/ObjectMappers.kt | 33 ++++++++++++------- .../api/models/sessions/ModelConfig.kt | 2 +- .../api/models/sessions/SessionActParams.kt | 2 +- .../browserbase/api/core/ObjectMappersTest.kt | 16 +++------ .../api/models/sessions/ModelConfigTest.kt | 17 +++++++--- stagehand-java-proguard-test/build.gradle.kts | 2 +- 8 files changed, 53 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index ee11525..29bd1d4 100644 --- a/README.md +++ b/README.md @@ -382,6 +382,8 @@ If the SDK threw an exception, but you're _certain_ the version is compatible, t > [!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. +Also note that there are bugs in older Jackson versions that can affect the SDK. We don't work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead. + ## Network options ### Retries diff --git a/stagehand-java-core/build.gradle.kts b/stagehand-java-core/build.gradle.kts index 38bcf47..3cfe35b 100644 --- a/stagehand-java-core/build.gradle.kts +++ b/stagehand-java-core/build.gradle.kts @@ -5,14 +5,16 @@ plugins { configurations.all { resolutionStrategy { - // Compile and test against a lower Jackson version to ensure we're compatible with it. - // We publish with a higher version (see below) to ensure users depend on a secure version by default. - force("com.fasterxml.jackson.core:jackson-core:2.13.4") - force("com.fasterxml.jackson.core:jackson-databind:2.13.4") - force("com.fasterxml.jackson.core:jackson-annotations:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4") - force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4") - force("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + // Compile and test against a lower Jackson version to ensure we're compatible with it. Note that + // we generally support 2.13.4, but test against 2.14.0 because 2.13.4 has some annoying (but + // niche) bugs (users should upgrade if they encounter them). We publish with a higher version + // (see below) to ensure users depend on a secure version by default. + force("com.fasterxml.jackson.core:jackson-core:2.14.0") + force("com.fasterxml.jackson.core:jackson-databind:2.14.0") + force("com.fasterxml.jackson.core:jackson-annotations:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.0") + force("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.0") + force("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt index 9ed574e..1d4e317 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt @@ -24,6 +24,7 @@ import java.io.InputStream import java.time.DateTimeException import java.time.LocalDate import java.time.LocalDateTime +import java.time.OffsetDateTime import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField @@ -36,7 +37,7 @@ fun jsonMapper(): JsonMapper = .addModule( SimpleModule() .addSerializer(InputStreamSerializer) - .addDeserializer(LocalDateTime::class.java, LenientLocalDateTimeDeserializer()) + .addDeserializer(OffsetDateTime::class.java, LenientOffsetDateTimeDeserializer()) ) .withCoercionConfig(LogicalType.Boolean) { it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -64,6 +65,12 @@ fun jsonMapper(): JsonMapper = .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) } + .withCoercionConfig(LogicalType.DateTime) { + it.setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) + } .withCoercionConfig(LogicalType.Array) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) .setCoercion(CoercionInputShape.Integer, CoercionAction.Fail) @@ -124,10 +131,10 @@ private object InputStreamSerializer : BaseSerializer(InputStream:: } /** - * A deserializer that can deserialize [LocalDateTime] from datetimes, dates, and zoned datetimes. + * A deserializer that can deserialize [OffsetDateTime] from datetimes, dates, and zoned datetimes. */ -private class LenientLocalDateTimeDeserializer : - StdDeserializer(LocalDateTime::class.java) { +private class LenientOffsetDateTimeDeserializer : + StdDeserializer(OffsetDateTime::class.java) { companion object { @@ -141,7 +148,7 @@ private class LenientLocalDateTimeDeserializer : override fun logicalType(): LogicalType = LogicalType.DateTime - override fun deserialize(p: JsonParser, context: DeserializationContext?): LocalDateTime { + override fun deserialize(p: JsonParser, context: DeserializationContext): OffsetDateTime { val exceptions = mutableListOf() for (formatter in DATE_TIME_FORMATTERS) { @@ -149,18 +156,20 @@ private class LenientLocalDateTimeDeserializer : val temporal = formatter.parse(p.text) return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal).atStartOfDay() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal) + else -> ZonedDateTime.from(temporal).toLocalDateTime() + } + .atZone(context.timeZone.toZoneId()) + .toOffsetDateTime() } catch (e: DateTimeException) { exceptions.add(e) } } - throw JsonParseException(p, "Cannot parse `LocalDateTime` from value: ${p.text}").apply { + throw JsonParseException(p, "Cannot parse `OffsetDateTime` from value: ${p.text}").apply { exceptions.forEach { addSuppressed(it) } } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index f8467e9..e104ae5 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -197,7 +197,7 @@ private constructor( .toList() return when (bestMatches.size) { // This can happen if what we're deserializing is completely incompatible with all - // the possible variants (e.g. deserializing from array). + // the possible variants (e.g. deserializing from boolean). 0 -> ModelConfig(_json = json) 1 -> bestMatches.single() // If there's more than one match with the highest validity, then use the first diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 92df30c..6a0794b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -742,7 +742,7 @@ private constructor( .toList() return when (bestMatches.size) { // This can happen if what we're deserializing is completely incompatible with - // all the possible variants (e.g. deserializing from array). + // all the possible variants (e.g. deserializing from boolean). 0 -> Input(_json = json) 1 -> bestMatches.single() // If there's more than one match with the highest validity, then use the first diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt index d405053..fed5676 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt @@ -3,7 +3,7 @@ package com.browserbase.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue -import java.time.LocalDateTime +import java.time.OffsetDateTime import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable @@ -58,14 +58,6 @@ internal class ObjectMappersTest { LONG to DOUBLE, LONG to INTEGER, CLASS to MAP, - // These aren't actually valid, but coercion configs don't work for String until - // v2.14.0: https://github.com/FasterXML/jackson-databind/issues/3240 - // We currently test on v2.13.4. - BOOLEAN to STRING, - FLOAT to STRING, - DOUBLE to STRING, - INTEGER to STRING, - LONG to STRING, ) } } @@ -84,7 +76,7 @@ internal class ObjectMappersTest { } } - enum class LenientLocalDateTimeTestCase(val string: String) { + enum class LenientOffsetDateTimeTestCase(val string: String) { DATE("1998-04-21"), DATE_TIME("1998-04-21T04:00:00"), ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), @@ -93,10 +85,10 @@ internal class ObjectMappersTest { @ParameterizedTest @EnumSource - fun readLocalDateTime_lenient(testCase: LenientLocalDateTimeTestCase) { + fun readOffsetDateTime_lenient(testCase: LenientOffsetDateTimeTestCase) { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + assertDoesNotThrow { jsonMapper().readValue(json) } } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index 0190f8e..467ac79 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -9,6 +9,8 @@ import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource internal class ModelConfigTest { @@ -74,10 +76,17 @@ internal class ModelConfigTest { assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) } - @Test - fun incompatibleJsonShapeDeserializesToUnknown() { - val value = JsonValue.from(listOf("invalid", "array")) - val modelConfig = jsonMapper().convertValue(value, jacksonTypeRef()) + enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { + BOOLEAN(JsonValue.from(false)), + INTEGER(JsonValue.from(-1)), + FLOAT(JsonValue.from(3.14)), + ARRAY(JsonValue.from(listOf("invalid", "array"))), + } + + @ParameterizedTest + @EnumSource + fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { + val modelConfig = jsonMapper().convertValue(testCase.value, jacksonTypeRef()) val e = assertThrows { modelConfig.validate() } assertThat(e).hasMessageStartingWith("Unknown ") diff --git a/stagehand-java-proguard-test/build.gradle.kts b/stagehand-java-proguard-test/build.gradle.kts index 9641bb2..1f6dfc6 100644 --- a/stagehand-java-proguard-test/build.gradle.kts +++ b/stagehand-java-proguard-test/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.assertj:assertj-core:3.25.3") - testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.4") + testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } tasks.shadowJar { From f2e4d43e0da60d01beafd720e350142e1352c8b6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:25:14 +0000 Subject: [PATCH 077/164] chore(internal): improve maven repo docs --- scripts/upload-artifacts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index df0c8d9..548d152 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -56,12 +56,13 @@ upload_file() { # Upload file upload_response=$(curl -v -X PUT \ --retry 5 \ + --retry-all-errors \ -D "$tmp_headers" \ -H "Content-Type: $content_type" \ --data-binary "@${file_name}" "$signed_url" 2>&1) if ! echo "$upload_response" | grep -q "HTTP/[0-9.]* 200"; then - log_error "Failed upload artifact file" "$tmp_headers" "$upload_response" + log_error "Failed to upload artifact file" "$tmp_headers" "$upload_response" fi # Insert small throttle to reduce rate limiting risk @@ -110,6 +111,10 @@ generate_instructions() { url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn' } } + +

Once you've added the repository, you can include dependencies from it as usual. See your + project README + for more details.

EOF From 6bd2965ac9aed35b9d5764adafd300b22898e624 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:30:33 +0000 Subject: [PATCH 078/164] fix(client): disallow coercion from float to int --- .../src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt | 1 + .../test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt index 1d4e317..06367fe 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt @@ -48,6 +48,7 @@ fun jsonMapper(): JsonMapper = } .withCoercionConfig(LogicalType.Integer) { it.setCoercion(CoercionInputShape.Boolean, CoercionAction.Fail) + .setCoercion(CoercionInputShape.Float, CoercionAction.Fail) .setCoercion(CoercionInputShape.String, CoercionAction.Fail) .setCoercion(CoercionInputShape.Array, CoercionAction.Fail) .setCoercion(CoercionInputShape.Object, CoercionAction.Fail) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt index fed5676..bc80611 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt @@ -46,11 +46,7 @@ internal class ObjectMappersTest { val VALID_CONVERSIONS = listOf( FLOAT to DOUBLE, - FLOAT to INTEGER, - FLOAT to LONG, DOUBLE to FLOAT, - DOUBLE to INTEGER, - DOUBLE to LONG, INTEGER to FLOAT, INTEGER to DOUBLE, INTEGER to LONG, From b4033565d0a461e04aaa33accc79d5f712e98ef6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:31:24 +0000 Subject: [PATCH 079/164] chore(internal): update `actions/checkout` version --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-sonatype.yml | 2 +- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e136c7c..377c7f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 @@ -47,7 +47,7 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 @@ -85,7 +85,7 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 67e28c7..874ace6 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Java uses: actions/setup-java@v4 diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index a6e0235..e71595c 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'browserbase/stagehand-java' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Check release environment run: | From 005208ee3066f8c2b3ed6f4a0ac85ec9cfbd5d6f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:33:18 +0000 Subject: [PATCH 080/164] fix(client): fully respect max retries fix(client): send retry count header for max retries 0 chore(internal): depend on packages directly in example --- .../api/client/okhttp/OkHttpClient.kt | 2 ++ .../api/core/http/RetryingHttpClient.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index 116714c..dadd500 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -234,6 +234,8 @@ private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClien fun build(): OkHttpClient = OkHttpClient( okhttp3.OkHttpClient.Builder() + // `RetryingHttpClient` handles retries if the user enabled them. + .retryOnConnectionFailure(false) .connectTimeout(timeout.connect()) .readTimeout(timeout.read()) .writeTimeout(timeout.write()) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt index 7e1a7aa..1305c6a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt @@ -31,10 +31,6 @@ private constructor( ) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.execute(request, requestOptions) - } - var modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -48,6 +44,10 @@ private constructor( modifiedRequest = setRetryCountHeader(modifiedRequest, retries) } + if (!isRetryable(modifiedRequest)) { + return httpClient.execute(modifiedRequest, requestOptions) + } + val response = try { val response = httpClient.execute(modifiedRequest, requestOptions) @@ -75,10 +75,6 @@ private constructor( request: HttpRequest, requestOptions: RequestOptions, ): CompletableFuture { - if (!isRetryable(request) || maxRetries <= 0) { - return httpClient.executeAsync(request, requestOptions) - } - val modifiedRequest = maybeAddIdempotencyHeader(request) // Don't send the current retry count in the headers if the caller set their own value. @@ -94,8 +90,12 @@ private constructor( val requestWithRetryCount = if (shouldSendRetryCount) setRetryCountHeader(request, retries) else request - return httpClient - .executeAsync(requestWithRetryCount, requestOptions) + val responseFuture = httpClient.executeAsync(requestWithRetryCount, requestOptions) + if (!isRetryable(requestWithRetryCount)) { + return responseFuture + } + + return responseFuture .handleAsync( fun( response: HttpResponse?, From 77004ca2e01c5e969034b501b8587b8f6e3327d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 05:34:12 +0000 Subject: [PATCH 081/164] chore(ci): upgrade `actions/setup-java` --- .github/workflows/ci.yml | 6 +++--- .github/workflows/publish-sonatype.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 377c7f1..49979dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | @@ -88,7 +88,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index 874ace6..e0e380c 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v6 - name: Set up Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: | From 84cf55c4068926637ae9f6ac29f62bfb2ab27eb5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 18:48:37 +0000 Subject: [PATCH 082/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 71adca4..7fb6541 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-07032b695bc66ecd76328d936b41e01cfad508a870928c09c185f5faa5ea66ab.yml openapi_spec_hash: fca4b895ce36ad547fb015c3dd38821f -config_hash: bf22187c626f0401180a332e3f3f6d8c +config_hash: 836c4460e94656a3e75bfe1eb8a677df From b12a7d860b526d0bbe7868825c0e33d925a6d846 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 19:15:34 +0000 Subject: [PATCH 083/164] feat: move Stainless compatibility transforms from gen-openapi.ts into stainless.yml --- .github/workflows/publish-sonatype.yml | 2 +- .stats.yml | 6 +- LICENSE | 202 ++++- README.md | 2 - build.gradle.kts | 13 + buildSrc/build.gradle.kts | 3 - .../src/main/kotlin/stagehand.java.gradle.kts | 9 + .../main/kotlin/stagehand.publish.gradle.kts | 105 ++- .../api/models/sessions/ModelConfig.kt | 808 +++++++----------- .../api/models/sessions/SessionActParams.kt | 18 - .../models/sessions/SessionExecuteParams.kt | 18 - .../models/sessions/SessionExtractParams.kt | 18 - .../models/sessions/SessionObserveParams.kt | 18 - .../api/models/sessions/SessionStartParams.kt | 17 +- .../api/models/sessions/ModelConfigTest.kt | 79 +- .../models/sessions/SessionActParamsTest.kt | 36 +- .../sessions/SessionExecuteParamsTest.kt | 36 +- .../sessions/SessionExtractParamsTest.kt | 36 +- .../sessions/SessionObserveParamsTest.kt | 36 +- .../api/services/ServiceParamsTest.kt | 10 +- .../services/async/SessionServiceAsyncTest.kt | 73 +- .../services/blocking/SessionServiceTest.kt | 73 +- .../api/proguard/ProGuardCompatibilityTest.kt | 15 - 23 files changed, 855 insertions(+), 778 deletions(-) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index e0e380c..d01e5dd 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -33,7 +33,7 @@ jobs: 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 + ./gradlew publish --no-configuration-cache env: SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index 7fb6541..9c0f6d9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-07032b695bc66ecd76328d936b41e01cfad508a870928c09c185f5faa5ea66ab.yml -openapi_spec_hash: fca4b895ce36ad547fb015c3dd38821f -config_hash: 836c4460e94656a3e75bfe1eb8a677df +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-d91dfd9ce727aefac56505ac86feb5cc665d3d5cef80ff17605f45e09b258251.yml +openapi_spec_hash: 0d1cae70e9d1debc5ac1a69fc665af37 +config_hash: 64c9cc393de93af70e11dbf0b1ba9388 diff --git a/LICENSE b/LICENSE index a7b82c2..d15d021 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,201 @@ -Copyright 2026 stagehand + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + 1. Definitions. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Stagehand + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 29bd1d4..9d564ca 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://docs.stagehand.dev) from applications written in Java. -The Stagehand Java SDK is similar to the Stagehand Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. - It is generated with [Stainless](https://www.stainless.com/). ## MCP Server diff --git a/build.gradle.kts b/build.gradle.kts index 49dfc3e..7c2c0c2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + id("io.github.gradle-nexus.publish-plugin") version "1.1.0" id("org.jetbrains.dokka") version "2.0.0" } @@ -34,3 +35,15 @@ tasks.named("dokkaJavadocCollector").configure { .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } + +nexusPublishing { + repositories { + sonatype { + nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) + snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) + + username.set(System.getenv("SONATYPE_USERNAME")) + password.set(System.getenv("SONATYPE_PASSWORD")) + } + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c6dc92e..0b14135 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,15 +1,12 @@ plugins { `kotlin-dsl` kotlin("jvm") version "1.9.20" - id("com.vanniktech.maven.publish") version "0.28.0" } repositories { gradlePluginPortal() - mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") - implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0") } diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts index 70fc33f..81d5d32 100644 --- a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -8,6 +8,11 @@ repositories { mavenCentral() } +configure { + withJavadocJar() + withSourcesJar() +} + java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) @@ -22,6 +27,10 @@ tasks.withType().configureEach { options.release.set(8) } +tasks.named("javadocJar") { + setZip64(true) +} + tasks.named("jar") { manifest { attributes(mapOf( diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index f45a9d7..facd8ed 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -1,71 +1,68 @@ -import com.vanniktech.maven.publish.JavadocJar -import com.vanniktech.maven.publish.KotlinJvm -import com.vanniktech.maven.publish.MavenPublishBaseExtension -import com.vanniktech.maven.publish.SonatypeHost - plugins { - id("com.vanniktech.maven.publish") -} - -publishing { - repositories { - if (project.hasProperty("publishLocal")) { - maven { - name = "LocalFileSystem" - url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") - } - } - } + `maven-publish` + signing } -repositories { - gradlePluginPortal() - mavenCentral() -} +configure { + publications { + register("maven") { + from(components["java"]) -extra["signingInMemoryKey"] = System.getenv("GPG_SIGNING_KEY") -extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") -extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") + pom { + name.set("Stagehand API") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + url.set("https://docs.stagehand.dev") -configure { - if (!project.hasProperty("publishLocal")) { - signAllPublications() - publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) - } + licenses { + license { + name.set("Apache-2.0") + } + } - coordinates(project.group.toString(), project.name, project.version.toString()) - configure( - KotlinJvm( - javadocJar = JavadocJar.Dokka("dokkaJavadoc"), - sourcesJar = true, - ) - ) + developers { + developer { + name.set("Stagehand") + } + } - pom { - name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") - url.set("https://docs.stagehand.dev") + scm { + connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + url.set("https://github.com/browserbase/stagehand-java") + } - licenses { - license { - name.set("MIT") + versionMapping { + allVariants { + fromResolutionResult() + } + } } } - - developers { - developer { - name.set("Stagehand") + } + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") } } + } +} - scm { - connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - url.set("https://github.com/browserbase/stagehand-java") - } +signing { + val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null } + val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null } + val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null } + if (signingKey != null && signingPassword != null) { + useInMemoryPgpKeys( + signingKeyId, + signingKey, + signingPassword, + ) + sign(publishing.publications["maven"]) } } -tasks.withType().configureEach { - isZip64 = true +tasks.named("publish") { + dependsOn(":closeAndReleaseSonatypeStagingRepository") } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index e104ae5..49a3d65 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -2,458 +2,372 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.BaseDeserializer -import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.allMaxBy import com.browserbase.api.core.checkRequired -import com.browserbase.api.core.getOrThrow import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.ObjectCodec -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import com.fasterxml.jackson.databind.annotation.JsonSerialize -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull -/** - * Model name string with provider prefix. Always use the format 'provider/model-name' (e.g., - * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') - */ -@JsonDeserialize(using = ModelConfig.Deserializer::class) -@JsonSerialize(using = ModelConfig.Serializer::class) class ModelConfig +@JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val string: String? = null, - private val modelConfigObject: ModelConfigObject? = null, - private val _json: JsonValue? = null, + private val modelName: JsonField, + private val apiKey: JsonField, + private val baseUrl: JsonField, + private val provider: JsonField, + private val additionalProperties: MutableMap, ) { + @JsonCreator + private constructor( + @JsonProperty("modelName") @ExcludeMissing modelName: JsonField = JsonMissing.of(), + @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), + @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), + @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), + ) : this(modelName, apiKey, baseUrl, provider, mutableMapOf()) + /** - * Model name string with provider prefix. Always use the format 'provider/model-name' (e.g., - * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') + * Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun string(): Optional = Optional.ofNullable(string) - - fun modelConfigObject(): Optional = Optional.ofNullable(modelConfigObject) - - fun isString(): Boolean = string != null - - fun isModelConfigObject(): Boolean = modelConfigObject != null + fun modelName(): String = modelName.getRequired("modelName") /** - * Model name string with provider prefix. Always use the format 'provider/model-name' (e.g., - * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') + * API key for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). */ - fun asString(): String = string.getOrThrow("string") - - fun asModelConfigObject(): ModelConfigObject = modelConfigObject.getOrThrow("modelConfigObject") - - fun _json(): Optional = Optional.ofNullable(_json) + fun apiKey(): Optional = apiKey.getOptional("apiKey") - fun accept(visitor: Visitor): T = - when { - string != null -> visitor.visitString(string) - modelConfigObject != null -> visitor.visitModelConfigObject(modelConfigObject) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false + /** + * Base URL for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun baseUrl(): Optional = baseUrl.getOptional("baseURL") - fun validate(): ModelConfig = apply { - if (validated) { - return@apply - } + /** + * AI provider for the model (or provide a baseURL endpoint instead) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun provider(): Optional = provider.getOptional("provider") - accept( - object : Visitor { - override fun visitString(string: String) {} + /** + * Returns the raw JSON value of [modelName]. + * + * Unlike [modelName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("modelName") @ExcludeMissing fun _modelName(): JsonField = modelName - override fun visitModelConfigObject(modelConfigObject: ModelConfigObject) { - modelConfigObject.validate() - } - } - ) - validated = true - } + /** + * Returns the raw JSON value of [apiKey]. + * + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } + /** + * Returns the raw JSON value of [baseUrl]. + * + * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl /** - * Returns a score indicating how many valid values are contained in this object recursively. + * Returns the raw JSON value of [provider]. * - * Used for best match union deserialization. + * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitString(string: String) = 1 + @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider - override fun visitModelConfigObject(modelConfigObject: ModelConfigObject) = - modelConfigObject.validity() + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - override fun unknown(json: JsonValue?) = 0 - } - ) + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } + fun toBuilder() = Builder().from(this) - return other is ModelConfig && - string == other.string && - modelConfigObject == other.modelConfigObject + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ModelConfig]. + * + * The following fields are required: + * ```java + * .modelName() + * ``` + */ + @JvmStatic fun builder() = Builder() } - override fun hashCode(): Int = Objects.hash(string, modelConfigObject) + /** A builder for [ModelConfig]. */ + class Builder internal constructor() { + + private var modelName: JsonField? = null + private var apiKey: JsonField = JsonMissing.of() + private var baseUrl: JsonField = JsonMissing.of() + private var provider: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - override fun toString(): String = - when { - string != null -> "ModelConfig{string=$string}" - modelConfigObject != null -> "ModelConfig{modelConfigObject=$modelConfigObject}" - _json != null -> "ModelConfig{_unknown=$_json}" - else -> throw IllegalStateException("Invalid ModelConfig") + @JvmSynthetic + internal fun from(modelConfig: ModelConfig) = apply { + modelName = modelConfig.modelName + apiKey = modelConfig.apiKey + baseUrl = modelConfig.baseUrl + provider = modelConfig.provider + additionalProperties = modelConfig.additionalProperties.toMutableMap() } - companion object { + /** Model name string with provider prefix (e.g., 'openai/gpt-5-nano') */ + fun modelName(modelName: String) = modelName(JsonField.of(modelName)) /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') + * Sets [Builder.modelName] to an arbitrary JSON value. + * + * You should usually call [Builder.modelName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - @JvmStatic fun ofString(string: String) = ModelConfig(string = string) + fun modelName(modelName: JsonField) = apply { this.modelName = modelName } - @JvmStatic - fun ofModelConfigObject(modelConfigObject: ModelConfigObject) = - ModelConfig(modelConfigObject = modelConfigObject) - } - - /** - * An interface that defines how to map each variant of [ModelConfig] to a value of type [T]. - */ - interface Visitor { + /** API key for the model provider */ + fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun visitString(string: String): T + fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } - fun visitModelConfigObject(modelConfigObject: ModelConfigObject): T + /** Base URL for the model provider */ + fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) /** - * Maps an unknown variant of [ModelConfig] to a value of type [T]. + * Sets [Builder.baseUrl] to an arbitrary JSON value. * - * An instance of [ModelConfig] can contain an unknown variant if it was deserialized from - * data that doesn't match any known variant. For example, if the SDK is on an older version - * than the API, then the API may respond with new variants that the SDK is unaware of. + * You should usually call [Builder.baseUrl] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + + /** AI provider for the model (or provide a baseURL endpoint instead) */ + fun provider(provider: Provider) = provider(JsonField.of(provider)) + + /** + * Sets [Builder.provider] to an arbitrary JSON value. * - * @throws StagehandInvalidDataException in the default implementation. + * You should usually call [Builder.provider] with a well-typed [Provider] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown ModelConfig: $json") + fun provider(provider: JsonField) = apply { this.provider = provider } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) } - } - internal class Deserializer : BaseDeserializer(ModelConfig::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): ModelConfig { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef())?.let { - ModelConfig(modelConfigObject = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - ModelConfig(string = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible with all - // the possible variants (e.g. deserializing from boolean). - 0 -> ModelConfig(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the first - // completely valid match, or simply the first match if none are completely valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) } - } - internal class Serializer : BaseSerializer(ModelConfig::class) { - - override fun serialize( - value: ModelConfig, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.string != null -> generator.writeObject(value.string) - value.modelConfigObject != null -> generator.writeObject(value.modelConfigObject) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid ModelConfig") - } + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) } - } - class ModelConfigObject - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val modelName: JsonField, - private val apiKey: JsonField, - private val baseUrl: JsonField, - private val provider: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("modelName") - @ExcludeMissing - modelName: JsonField = JsonMissing.of(), - @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), - @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), - @JsonProperty("provider") - @ExcludeMissing - provider: JsonField = JsonMissing.of(), - ) : this(modelName, apiKey, baseUrl, provider, mutableMapOf()) + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). - */ - fun modelName(): String = modelName.getRequired("modelName") + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } /** - * API key for the model provider + * Returns an immutable instance of [ModelConfig]. * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun apiKey(): Optional = apiKey.getOptional("apiKey") - - /** - * Base URL for the model provider + * Further updates to this [Builder] will not mutate the returned instance. * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun baseUrl(): Optional = baseUrl.getOptional("baseURL") - - /** - * AI provider for the model (or provide a baseURL endpoint instead) + * The following fields are required: + * ```java + * .modelName() + * ``` * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws IllegalStateException if any required field is unset. */ - fun provider(): Optional = provider.getOptional("provider") + fun build(): ModelConfig = + ModelConfig( + checkRequired("modelName", modelName), + apiKey, + baseUrl, + provider, + additionalProperties.toMutableMap(), + ) + } - /** - * Returns the raw JSON value of [modelName]. - * - * Unlike [modelName], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("modelName") @ExcludeMissing fun _modelName(): JsonField = modelName + private var validated: Boolean = false - /** - * Returns the raw JSON value of [apiKey]. - * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + fun validate(): ModelConfig = apply { + if (validated) { + return@apply + } - /** - * Returns the raw JSON value of [baseUrl]. - * - * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + modelName() + apiKey() + baseUrl() + provider().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (modelName.asKnown().isPresent) 1 else 0) + + (if (apiKey.asKnown().isPresent) 1 else 0) + + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (provider.asKnown().getOrNull()?.validity() ?: 0) + + /** AI provider for the model (or provide a baseURL endpoint instead) */ + class Provider @JsonCreator private constructor(private val value: JsonField) : Enum { /** - * Returns the raw JSON value of [provider]. + * Returns this class instance's raw value. * - * Unlike [provider], this method doesn't throw if the JSON field has an unexpected type. + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. */ - @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + companion object { - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + @JvmField val OPENAI = of("openai") - fun toBuilder() = Builder().from(this) + @JvmField val ANTHROPIC = of("anthropic") - companion object { + @JvmField val GOOGLE = of("google") + + @JvmField val MICROSOFT = of("microsoft") - /** - * Returns a mutable builder for constructing an instance of [ModelConfigObject]. - * - * The following fields are required: - * ```java - * .modelName() - * ``` - */ - @JvmStatic fun builder() = Builder() + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) } - /** A builder for [ModelConfigObject]. */ - class Builder internal constructor() { - - private var modelName: JsonField? = null - private var apiKey: JsonField = JsonMissing.of() - private var baseUrl: JsonField = JsonMissing.of() - private var provider: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(modelConfigObject: ModelConfigObject) = apply { - modelName = modelConfigObject.modelName - apiKey = modelConfigObject.apiKey - baseUrl = modelConfigObject.baseUrl - provider = modelConfigObject.provider - additionalProperties = modelConfigObject.additionalProperties.toMutableMap() - } + /** An enum containing [Provider]'s known values. */ + enum class Known { + OPENAI, + ANTHROPIC, + GOOGLE, + MICROSOFT, + } - /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - */ - fun modelName(modelName: String) = modelName(JsonField.of(modelName)) - - /** - * Sets [Builder.modelName] to an arbitrary JSON value. - * - * You should usually call [Builder.modelName] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun modelName(modelName: JsonField) = apply { this.modelName = modelName } - - /** API key for the model provider */ - fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) - - /** - * Sets [Builder.apiKey] to an arbitrary JSON value. - * - * You should usually call [Builder.apiKey] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } - - /** Base URL for the model provider */ - fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) - - /** - * Sets [Builder.baseUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.baseUrl] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - - /** AI provider for the model (or provide a baseURL endpoint instead) */ - fun provider(provider: Provider) = provider(JsonField.of(provider)) - - /** - * Sets [Builder.provider] to an arbitrary JSON value. - * - * You should usually call [Builder.provider] with a well-typed [Provider] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun provider(provider: JsonField) = apply { this.provider = provider } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** + * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Provider] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPENAI, + ANTHROPIC, + GOOGLE, + MICROSOFT, + /** An enum member indicating that [Provider] was instantiated with an unknown value. */ + _UNKNOWN, + } - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPENAI -> Value.OPENAI + ANTHROPIC -> Value.ANTHROPIC + GOOGLE -> Value.GOOGLE + MICROSOFT -> Value.MICROSOFT + else -> Value._UNKNOWN } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + OPENAI -> Known.OPENAI + ANTHROPIC -> Known.ANTHROPIC + GOOGLE -> Known.GOOGLE + MICROSOFT -> Known.MICROSOFT + else -> throw StagehandInvalidDataException("Unknown Provider: $value") } - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") } - /** - * Returns an immutable instance of [ModelConfigObject]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .modelName() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ModelConfigObject = - ModelConfigObject( - checkRequired("modelName", modelName), - apiKey, - baseUrl, - provider, - additionalProperties.toMutableMap(), - ) - } - private var validated: Boolean = false - fun validate(): ModelConfigObject = apply { + fun validate(): Provider = apply { if (validated) { return@apply } - modelName() - apiKey() - baseUrl() - provider().ifPresent { it.validate() } + known() validated = true } @@ -471,176 +385,40 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic - internal fun validity(): Int = - (if (modelName.asKnown().isPresent) 1 else 0) + - (if (apiKey.asKnown().isPresent) 1 else 0) + - (if (baseUrl.asKnown().isPresent) 1 else 0) + - (provider.asKnown().getOrNull()?.validity() ?: 0) - - /** AI provider for the model (or provide a baseURL endpoint instead) */ - class Provider @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val OPENAI = of("openai") - - @JvmField val ANTHROPIC = of("anthropic") - - @JvmField val GOOGLE = of("google") - - @JvmField val MICROSOFT = of("microsoft") - - @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) - } - - /** An enum containing [Provider]'s known values. */ - enum class Known { - OPENAI, - ANTHROPIC, - GOOGLE, - MICROSOFT, - } - - /** - * An enum containing [Provider]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Provider] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if - * the SDK is on an older version than the API, then the API may respond with new - * members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - OPENAI, - ANTHROPIC, - GOOGLE, - MICROSOFT, - /** - * An enum member indicating that [Provider] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you - * want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - OPENAI -> Value.OPENAI - ANTHROPIC -> Value.ANTHROPIC - GOOGLE -> Value.GOOGLE - MICROSOFT -> Value.MICROSOFT - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. - * - * @throws StagehandInvalidDataException if this class instance's value is a not a known - * member. - */ - fun known(): Known = - when (this) { - OPENAI -> Known.OPENAI - ANTHROPIC -> Known.ANTHROPIC - GOOGLE -> Known.GOOGLE - MICROSOFT -> Known.MICROSOFT - else -> throw StagehandInvalidDataException("Unknown Provider: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws StagehandInvalidDataException if this class instance's value does not have - * the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - StagehandInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Provider = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Provider && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is ModelConfigObject && - modelName == other.modelName && - apiKey == other.apiKey && - baseUrl == other.baseUrl && - provider == other.provider && - additionalProperties == other.additionalProperties + return other is Provider && value == other.value } - private val hashCode: Int by lazy { - Objects.hash(modelName, apiKey, baseUrl, provider, additionalProperties) + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true } - override fun hashCode(): Int = hashCode + return other is ModelConfig && + modelName == other.modelName && + apiKey == other.apiKey && + baseUrl == other.baseUrl && + provider == other.provider && + additionalProperties == other.additionalProperties + } - override fun toString() = - "ModelConfigObject{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, provider=$provider, additionalProperties=$additionalProperties}" + private val hashCode: Int by lazy { + Objects.hash(modelName, apiKey, baseUrl, provider, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, provider=$provider, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 6a0794b..b8938ca 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -789,10 +789,6 @@ private constructor( ) : this(model, timeout, variables, mutableMapOf()) /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -871,11 +867,6 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } - /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -887,15 +878,6 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) - - /** - * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. - */ - fun model(modelConfigObject: ModelConfig.ModelConfigObject) = - model(ModelConfig.ofModelConfigObject(modelConfigObject)) - /** Timeout in ms for the action */ fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 65c7508..be1c84c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -623,10 +623,6 @@ private constructor( fun cua(): Optional = cua.getOptional("cua") /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -727,11 +723,6 @@ private constructor( */ fun cua(cua: JsonField) = apply { this.cua = cua } - /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -743,15 +734,6 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) - - /** - * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. - */ - fun model(modelConfigObject: ModelConfig.ModelConfigObject) = - model(ModelConfig.ofModelConfigObject(modelConfigObject)) - /** AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) */ fun provider(provider: Provider) = provider(JsonField.of(provider)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 45507fe..03cac9e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -628,10 +628,6 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -708,11 +704,6 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } - /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -724,15 +715,6 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) - - /** - * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. - */ - fun model(modelConfigObject: ModelConfig.ModelConfigObject) = - model(ModelConfig.ofModelConfigObject(modelConfigObject)) - /** CSS selector to scope extraction to a specific element */ fun selector(selector: String) = selector(JsonField.of(selector)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 4ba5e2f..200b881 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -568,10 +568,6 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ @@ -648,11 +644,6 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } - /** - * Model name string with provider prefix. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - */ fun model(model: ModelConfig) = model(JsonField.of(model)) /** @@ -664,15 +655,6 @@ private constructor( */ fun model(model: JsonField) = apply { this.model = model } - /** Alias for calling [model] with `ModelConfig.ofString(string)`. */ - fun model(string: String) = model(ModelConfig.ofString(string)) - - /** - * Alias for calling [model] with `ModelConfig.ofModelConfigObject(modelConfigObject)`. - */ - fun model(modelConfigObject: ModelConfig.ModelConfigObject) = - model(ModelConfig.ofModelConfigObject(modelConfigObject)) - /** CSS selector to scope observation to a specific element */ fun selector(selector: String) = selector(JsonField.of(selector)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 85b3c01..caf2501 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -50,8 +50,7 @@ private constructor( fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) /** - * Model name to use for AI operations. Always use the format 'provider/model-name' (e.g., - * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') + * Model name to use for AI operations * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -277,10 +276,7 @@ private constructor( */ fun body(body: Body) = apply { this.body = body.toBuilder() } - /** - * Model name to use for AI operations. Always use the format 'provider/model-name' (e.g., - * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') - */ + /** Model name to use for AI operations */ fun modelName(modelName: String) = apply { body.modelName(modelName) } /** @@ -644,8 +640,7 @@ private constructor( ) /** - * Model name to use for AI operations. Always use the format 'provider/model-name' (e.g., - * 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', 'google/gemini-2.0-flash') + * Model name to use for AI operations * * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). @@ -887,11 +882,7 @@ private constructor( additionalProperties = body.additionalProperties.toMutableMap() } - /** - * Model name to use for AI operations. Always use the format 'provider/model-name' - * (e.g., 'openai/gpt-4o', 'anthropic/claude-sonnet-4-5-20250929', - * 'google/gemini-2.0-flash') - */ + /** Model name to use for AI operations */ fun modelName(modelName: String) = modelName(JsonField.of(modelName)) /** diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index 467ac79..cd7f6b7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -2,70 +2,39 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper -import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.EnumSource internal class ModelConfigTest { @Test - fun ofString() { - val string = "openai/gpt-4o" - - val modelConfig = ModelConfig.ofString(string) - - assertThat(modelConfig.string()).contains(string) - assertThat(modelConfig.modelConfigObject()).isEmpty - } - - @Test - fun ofStringRoundtrip() { - val jsonMapper = jsonMapper() - val modelConfig = ModelConfig.ofString("openai/gpt-4o") - - val roundtrippedModelConfig = - jsonMapper.readValue( - jsonMapper.writeValueAsString(modelConfig), - jacksonTypeRef(), - ) - - assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) - } - - @Test - fun ofModelConfigObject() { - val modelConfigObject = - ModelConfig.ModelConfigObject.builder() - .modelName("openai/gpt-4o") + fun create() { + val modelConfig = + ModelConfig.builder() + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") - .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) + .provider(ModelConfig.Provider.OPENAI) .build() - val modelConfig = ModelConfig.ofModelConfigObject(modelConfigObject) - - assertThat(modelConfig.string()).isEmpty - assertThat(modelConfig.modelConfigObject()).contains(modelConfigObject) + assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5-nano") + assertThat(modelConfig.apiKey()).contains("sk-some-openai-api-key") + assertThat(modelConfig.baseUrl()).contains("https://api.openai.com/v1") + assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI) } @Test - fun ofModelConfigObjectRoundtrip() { + fun roundtrip() { val jsonMapper = jsonMapper() val modelConfig = - ModelConfig.ofModelConfigObject( - ModelConfig.ModelConfigObject.builder() - .modelName("openai/gpt-4o") - .apiKey("sk-some-openai-api-key") - .baseUrl("https://api.openai.com/v1") - .provider(ModelConfig.ModelConfigObject.Provider.OPENAI) - .build() - ) + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() val roundtrippedModelConfig = jsonMapper.readValue( @@ -75,20 +44,4 @@ internal class ModelConfigTest { assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) } - - enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { - BOOLEAN(JsonValue.from(false)), - INTEGER(JsonValue.from(-1)), - FLOAT(JsonValue.from(3.14)), - ARRAY(JsonValue.from(listOf("invalid", "array"))), - } - - @ParameterizedTest - @EnumSource - fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { - val modelConfig = jsonMapper().convertValue(testCase.value, jacksonTypeRef()) - - val e = assertThrows { modelConfig.validate() } - assertThat(e).hasMessageStartingWith("Unknown ") - } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index aec22f7..9d1e452 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -18,7 +18,14 @@ internal class SessionActParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -53,7 +60,14 @@ internal class SessionActParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -92,7 +106,14 @@ internal class SessionActParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -111,7 +132,14 @@ internal class SessionActParamsTest { assertThat(body.options()) .contains( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 6b36c20..6b4edd1 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -16,7 +16,14 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -63,7 +70,14 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -114,7 +128,14 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -137,7 +158,14 @@ internal class SessionExecuteParamsTest { .isEqualTo( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 1ee8821..3061c8d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -18,7 +18,14 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -51,7 +58,14 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -88,7 +102,14 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -108,7 +129,14 @@ internal class SessionExtractParamsTest { assertThat(body.options()) .contains( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 28cfb46..f238c0e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -17,7 +17,14 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() @@ -45,7 +52,14 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() @@ -77,7 +91,14 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() @@ -91,7 +112,14 @@ internal class SessionObserveParamsTest { assertThat(body.options()) .contains( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index b01ce5f..58471d6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -5,6 +5,7 @@ package com.browserbase.api.services import com.browserbase.api.client.StagehandClient import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.ModelConfig import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionStartParams import com.github.tomakehurst.wiremock.client.WireMock.anyUrl @@ -217,7 +218,14 @@ internal class ServiceParamsTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index bd4953d..89b8720 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -5,6 +5,7 @@ package com.browserbase.api.services.async import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.ModelConfig import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionEndParams import com.browserbase.api.models.sessions.SessionExecuteParams @@ -40,7 +41,14 @@ internal class SessionServiceAsyncTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -77,7 +85,14 @@ internal class SessionServiceAsyncTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -139,7 +154,14 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -181,7 +203,14 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -225,7 +254,14 @@ internal class SessionServiceAsyncTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -263,7 +299,14 @@ internal class SessionServiceAsyncTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -336,7 +379,14 @@ internal class SessionServiceAsyncTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() @@ -369,7 +419,14 @@ internal class SessionServiceAsyncTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 41e40f0..7aa8070 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -5,6 +5,7 @@ package com.browserbase.api.services.blocking import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue +import com.browserbase.api.models.sessions.ModelConfig import com.browserbase.api.models.sessions.SessionActParams import com.browserbase.api.models.sessions.SessionEndParams import com.browserbase.api.models.sessions.SessionExecuteParams @@ -40,7 +41,14 @@ internal class SessionServiceTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -76,7 +84,14 @@ internal class SessionServiceTest { .frameId("frameId") .options( SessionActParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .timeout(30000.0) .variables( SessionActParams.Options.Variables.builder() @@ -137,7 +152,14 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -178,7 +200,14 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) .systemPrompt("systemPrompt") .build() @@ -222,7 +251,14 @@ internal class SessionServiceTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -259,7 +295,14 @@ internal class SessionServiceTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("#main-content") .timeout(30000.0) .build() @@ -331,7 +374,14 @@ internal class SessionServiceTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() @@ -363,7 +413,14 @@ internal class SessionServiceTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() - .model("openai/gpt-4o") + .model( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .selector("nav") .timeout(30000.0) .build() diff --git a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt index 7db4e74..1099052 100644 --- a/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt +++ b/stagehand-java-proguard-test/src/test/kotlin/com/browserbase/api/proguard/ProGuardCompatibilityTest.kt @@ -5,7 +5,6 @@ package com.browserbase.api.proguard import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.jsonMapper import com.browserbase.api.models.sessions.Action -import com.browserbase.api.models.sessions.ModelConfig import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import kotlin.reflect.full.memberFunctions import kotlin.reflect.jvm.javaMethod @@ -73,18 +72,4 @@ internal class ProGuardCompatibilityTest { assertThat(roundtrippedAction).isEqualTo(action) } - - @Test - fun modelConfigRoundtrip() { - val jsonMapper = jsonMapper() - val modelConfig = ModelConfig.ofString("openai/gpt-4o") - - val roundtrippedModelConfig = - jsonMapper.readValue( - jsonMapper.writeValueAsString(modelConfig), - jacksonTypeRef(), - ) - - assertThat(roundtrippedModelConfig).isEqualTo(modelConfig) - } } From 1d927b5ab4653a4887f8a3eec1985420b57f1d27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 23:44:35 +0000 Subject: [PATCH 084/164] feat: End endpoint cleanup --- .stats.yml | 4 +- .../api/models/sessions/SessionEndParams.kt | 206 ++++-------------- .../api/models/sessions/SessionStartParams.kt | 36 ++- .../services/async/SessionServiceAsyncImpl.kt | 2 +- .../services/blocking/SessionServiceImpl.kt | 2 +- .../models/sessions/SessionEndParamsTest.kt | 24 -- .../models/sessions/SessionStartParamsTest.kt | 4 + .../api/services/ErrorHandlingTest.kt | 17 ++ .../api/services/ServiceParamsTest.kt | 1 + .../services/async/SessionServiceAsyncTest.kt | 2 +- .../services/blocking/SessionServiceTest.kt | 2 +- 11 files changed, 104 insertions(+), 196 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9c0f6d9..1c9fda1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-d91dfd9ce727aefac56505ac86feb5cc665d3d5cef80ff17605f45e09b258251.yml -openapi_spec_hash: 0d1cae70e9d1debc5ac1a69fc665af37 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-22af3433e4e2d94d5ba19598d795e91939118eb58af20179f2b07c916907c0b6.yml +openapi_spec_hash: a1ca99a2148ba2eddd0f0d8aab133a35 config_hash: 64c9cc393de93af70e11dbf0b1ba9388 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index 2114c89..cf9a245 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -3,19 +3,14 @@ package com.browserbase.api.models.sessions import com.browserbase.api.core.Enum -import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField -import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException -import com.fasterxml.jackson.annotation.JsonAnyGetter -import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty -import java.util.Collections import java.util.Objects import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -25,9 +20,9 @@ class SessionEndParams private constructor( private val id: String?, private val xStreamResponse: XStreamResponse?, - private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, ) : Params { /** Unique session identifier */ @@ -36,9 +31,8 @@ private constructor( /** Whether to stream the response via SSE */ fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) - fun __forceBody(): JsonValue = body.__forceBody() - - fun _additionalBodyProperties(): Map = body._additionalProperties() + /** Additional body properties to send with the request. */ + fun _additionalBodyProperties(): Map = additionalBodyProperties /** Additional headers to send with the request. */ fun _additionalHeaders(): Headers = additionalHeaders @@ -61,17 +55,17 @@ private constructor( private var id: String? = null private var xStreamResponse: XStreamResponse? = null - private var body: Body.Builder = Body.builder() private var additionalHeaders: Headers.Builder = Headers.builder() private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(sessionEndParams: SessionEndParams) = apply { id = sessionEndParams.id xStreamResponse = sessionEndParams.xStreamResponse - body = sessionEndParams.body.toBuilder() additionalHeaders = sessionEndParams.additionalHeaders.toBuilder() additionalQueryParams = sessionEndParams.additionalQueryParams.toBuilder() + additionalBodyProperties = sessionEndParams.additionalBodyProperties.toMutableMap() } /** Unique session identifier */ @@ -89,36 +83,6 @@ private constructor( fun xStreamResponse(xStreamResponse: Optional) = xStreamResponse(xStreamResponse.getOrNull()) - /** - * Sets the entire request body. - * - * This is generally only useful if you are already constructing the body separately. - * Otherwise, it's more convenient to use the top-level setters instead: - * - [_forceBody] - */ - fun body(body: Body) = apply { this.body = body.toBuilder() } - - fun _forceBody(_forceBody: JsonValue) = apply { body._forceBody(_forceBody) } - - fun additionalBodyProperties(additionalBodyProperties: Map) = apply { - body.additionalProperties(additionalBodyProperties) - } - - fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { - body.putAdditionalProperty(key, value) - } - - fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = - apply { - body.putAllAdditionalProperties(additionalBodyProperties) - } - - fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } - - fun removeAllAdditionalBodyProperties(keys: Set) = apply { - body.removeAllAdditionalProperties(keys) - } - fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() putAllAdditionalHeaders(additionalHeaders) @@ -217,6 +181,28 @@ private constructor( additionalQueryParams.removeAll(keys) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + /** * Returns an immutable instance of [SessionEndParams]. * @@ -226,13 +212,14 @@ private constructor( SessionEndParams( id, xStreamResponse, - body.build(), additionalHeaders.build(), additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), ) } - fun _body(): Body = body + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) fun _pathParam(index: Int): String = when (index) { @@ -250,123 +237,6 @@ private constructor( override fun _queryParams(): QueryParams = additionalQueryParams - class Body - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val _forceBody: JsonValue, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("_forceBody") @ExcludeMissing _forceBody: JsonValue = JsonMissing.of() - ) : this(_forceBody, mutableMapOf()) - - @JsonProperty("_forceBody") @ExcludeMissing fun __forceBody(): JsonValue = _forceBody - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Body]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Body]. */ - class Builder internal constructor() { - - private var _forceBody: JsonValue = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(body: Body) = apply { - _forceBody = body._forceBody - additionalProperties = body.additionalProperties.toMutableMap() - } - - fun _forceBody(_forceBody: JsonValue) = apply { this._forceBody = _forceBody } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Body]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Body = Body(_forceBody, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Body = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = 0 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Body && - _forceBody == other._forceBody && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(_forceBody, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Body{_forceBody=$_forceBody, additionalProperties=$additionalProperties}" - } - /** Whether to stream the response via SSE */ class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -507,14 +377,20 @@ private constructor( return other is SessionEndParams && id == other.id && xStreamResponse == other.xStreamResponse && - body == other.body && additionalHeaders == other.additionalHeaders && - additionalQueryParams == other.additionalQueryParams + additionalQueryParams == other.additionalQueryParams && + additionalBodyProperties == other.additionalBodyProperties } override fun hashCode(): Int = - Objects.hash(id, xStreamResponse, body, additionalHeaders, additionalQueryParams) + Objects.hash( + id, + xStreamResponse, + additionalHeaders, + additionalQueryParams, + additionalBodyProperties, + ) override fun toString() = - "SessionEndParams{id=$id, xStreamResponse=$xStreamResponse, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "SessionEndParams{id=$id, xStreamResponse=$xStreamResponse, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index caf2501..f177a4e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -1384,6 +1384,7 @@ private constructor( private val ignoreDefaultArgs: JsonField, private val ignoreHttpsErrors: JsonField, private val locale: JsonField, + private val port: JsonField, private val preserveUserDataDir: JsonField, private val proxy: JsonField, private val userDataDir: JsonField, @@ -1435,6 +1436,7 @@ private constructor( @JsonProperty("locale") @ExcludeMissing locale: JsonField = JsonMissing.of(), + @JsonProperty("port") @ExcludeMissing port: JsonField = JsonMissing.of(), @JsonProperty("preserveUserDataDir") @ExcludeMissing preserveUserDataDir: JsonField = JsonMissing.of(), @@ -1460,6 +1462,7 @@ private constructor( ignoreDefaultArgs, ignoreHttpsErrors, locale, + port, preserveUserDataDir, proxy, userDataDir, @@ -1557,6 +1560,12 @@ private constructor( */ fun locale(): Optional = locale.getOptional("locale") + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun port(): Optional = port.getOptional("port") + /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. * if the server responded with an unexpected value). @@ -1707,6 +1716,13 @@ private constructor( */ @JsonProperty("locale") @ExcludeMissing fun _locale(): JsonField = locale + /** + * Returns the raw JSON value of [port]. + * + * Unlike [port], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("port") @ExcludeMissing fun _port(): JsonField = port + /** * Returns the raw JSON value of [preserveUserDataDir]. * @@ -1779,6 +1795,7 @@ private constructor( private var ignoreDefaultArgs: JsonField = JsonMissing.of() private var ignoreHttpsErrors: JsonField = JsonMissing.of() private var locale: JsonField = JsonMissing.of() + private var port: JsonField = JsonMissing.of() private var preserveUserDataDir: JsonField = JsonMissing.of() private var proxy: JsonField = JsonMissing.of() private var userDataDir: JsonField = JsonMissing.of() @@ -1801,6 +1818,7 @@ private constructor( ignoreDefaultArgs = launchOptions.ignoreDefaultArgs ignoreHttpsErrors = launchOptions.ignoreHttpsErrors locale = launchOptions.locale + port = launchOptions.port preserveUserDataDir = launchOptions.preserveUserDataDir proxy = launchOptions.proxy userDataDir = launchOptions.userDataDir @@ -2011,6 +2029,17 @@ private constructor( */ fun locale(locale: JsonField) = apply { this.locale = locale } + fun port(port: Double) = port(JsonField.of(port)) + + /** + * Sets [Builder.port] to an arbitrary JSON value. + * + * You should usually call [Builder.port] with a well-typed [Double] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun port(port: JsonField) = apply { this.port = port } + fun preserveUserDataDir(preserveUserDataDir: Boolean) = preserveUserDataDir(JsonField.of(preserveUserDataDir)) @@ -2103,6 +2132,7 @@ private constructor( ignoreDefaultArgs, ignoreHttpsErrors, locale, + port, preserveUserDataDir, proxy, userDataDir, @@ -2132,6 +2162,7 @@ private constructor( ignoreDefaultArgs().ifPresent { it.validate() } ignoreHttpsErrors() locale() + port() preserveUserDataDir() proxy().ifPresent { it.validate() } userDataDir() @@ -2169,6 +2200,7 @@ private constructor( (ignoreDefaultArgs.asKnown().getOrNull()?.validity() ?: 0) + (if (ignoreHttpsErrors.asKnown().isPresent) 1 else 0) + (if (locale.asKnown().isPresent) 1 else 0) + + (if (port.asKnown().isPresent) 1 else 0) + (if (preserveUserDataDir.asKnown().isPresent) 1 else 0) + (proxy.asKnown().getOrNull()?.validity() ?: 0) + (if (userDataDir.asKnown().isPresent) 1 else 0) + @@ -2852,6 +2884,7 @@ private constructor( ignoreDefaultArgs == other.ignoreDefaultArgs && ignoreHttpsErrors == other.ignoreHttpsErrors && locale == other.locale && + port == other.port && preserveUserDataDir == other.preserveUserDataDir && proxy == other.proxy && userDataDir == other.userDataDir && @@ -2875,6 +2908,7 @@ private constructor( ignoreDefaultArgs, ignoreHttpsErrors, locale, + port, preserveUserDataDir, proxy, userDataDir, @@ -2886,7 +2920,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}" + "LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, port=$port, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}" } /** Browser type to use */ diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 6b354a0..82062e4 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -250,7 +250,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "end") - .body(json(clientOptions.jsonMapper, params._body())) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } .build() .prepareAsync(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index f064761..4bfce1b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -223,7 +223,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "end") - .body(json(clientOptions.jsonMapper, params._body())) + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } .build() .prepare(clientOptions, params) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt index 5d789fc..43a69e2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionEndParamsTest.kt @@ -2,7 +2,6 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -14,7 +13,6 @@ internal class SessionEndParamsTest { SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - ._forceBody(JsonValue.from(mapOf())) .build() } @@ -33,7 +31,6 @@ internal class SessionEndParamsTest { SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - ._forceBody(JsonValue.from(mapOf())) .build() val headers = params._headers() @@ -49,25 +46,4 @@ internal class SessionEndParamsTest { assertThat(headers).isEqualTo(Headers.builder().build()) } - - @Test - fun body() { - val params = - SessionEndParams.builder() - .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") - .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - ._forceBody(JsonValue.from(mapOf())) - .build() - - val body = params._body() - - assertThat(body.__forceBody()).isEqualTo(JsonValue.from(mapOf())) - } - - @Test - fun bodyWithoutOptionalFields() { - val params = SessionEndParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() - - val body = params._body() - } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index d3cd55c..e22e941 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -34,6 +34,7 @@ internal class SessionStartParamsTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -179,6 +180,7 @@ internal class SessionStartParamsTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -341,6 +343,7 @@ internal class SessionStartParamsTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -487,6 +490,7 @@ internal class SessionStartParamsTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 8f3f827..a28b993 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -96,6 +96,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -272,6 +273,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -448,6 +450,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -624,6 +627,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -800,6 +804,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -976,6 +981,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -1152,6 +1158,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -1328,6 +1335,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -1504,6 +1512,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -1680,6 +1689,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -1856,6 +1866,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -2032,6 +2043,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -2208,6 +2220,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -2384,6 +2397,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -2560,6 +2574,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -2736,6 +2751,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() @@ -2910,6 +2926,7 @@ internal class ErrorHandlingTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 58471d6..61376c2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -70,6 +70,7 @@ internal class ServiceParamsTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 89b8720..b66ee9e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -126,7 +126,6 @@ internal class SessionServiceAsyncTest { SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - ._forceBody(JsonValue.from(mapOf())) .build() ) @@ -476,6 +475,7 @@ internal class SessionServiceAsyncTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 7aa8070..c422457 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -125,7 +125,6 @@ internal class SessionServiceTest { SessionEndParams.builder() .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") .xStreamResponse(SessionEndParams.XStreamResponse.TRUE) - ._forceBody(JsonValue.from(mapOf())) .build() ) @@ -470,6 +469,7 @@ internal class SessionServiceTest { .ignoreDefaultArgs(true) .ignoreHttpsErrors(true) .locale("locale") + .port(0.0) .preserveUserDataDir(true) .proxy( SessionStartParams.Browser.LaunchOptions.Proxy.builder() From 7fcd3ccf535f13ae8151cf47c47916044a247695 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 01:00:55 +0000 Subject: [PATCH 085/164] feat: [feat]: add support for local caching of agent when using api (2) --- .stats.yml | 4 +- .../models/sessions/SessionExecuteParams.kt | 77 +++++- .../models/sessions/SessionExecuteResponse.kt | 239 +++++++++++++++++- .../sessions/SessionExecuteParamsTest.kt | 4 + .../sessions/SessionExecuteResponseTest.kt | 18 ++ .../services/async/SessionServiceAsyncTest.kt | 2 + .../services/blocking/SessionServiceTest.kt | 2 + 7 files changed, 334 insertions(+), 12 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1c9fda1..babf0f2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-22af3433e4e2d94d5ba19598d795e91939118eb58af20179f2b07c916907c0b6.yml -openapi_spec_hash: a1ca99a2148ba2eddd0f0d8aab133a35 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2132f9afd90a3b3c35b772f0de3ac8432cfe46ecfa22ec9c1ed4a3d0eda1ad41.yml +openapi_spec_hash: 6da568c2948d8ab6000db4291e15a033 config_hash: 64c9cc393de93af70e11dbf0b1ba9388 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index be1c84c..c62d819 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -57,6 +57,14 @@ private constructor( */ fun frameId(): Optional = body.frameId() + /** + * If true, the server captures a cache entry and returns it to the client + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun shouldCache(): Optional = body.shouldCache() + /** * Returns the raw JSON value of [agentConfig]. * @@ -78,6 +86,13 @@ private constructor( */ fun _frameId(): JsonField = body._frameId() + /** + * Returns the raw JSON value of [shouldCache]. + * + * Unlike [shouldCache], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _shouldCache(): JsonField = body._shouldCache() + fun _additionalBodyProperties(): Map = body._additionalProperties() /** Additional headers to send with the request. */ @@ -143,6 +158,7 @@ private constructor( * - [agentConfig] * - [executeOptions] * - [frameId] + * - [shouldCache] */ fun body(body: Body) = apply { this.body = body.toBuilder() } @@ -188,6 +204,18 @@ private constructor( */ fun frameId(frameId: JsonField) = apply { body.frameId(frameId) } + /** If true, the server captures a cache entry and returns it to the client */ + fun shouldCache(shouldCache: Boolean) = apply { body.shouldCache(shouldCache) } + + /** + * Sets [Builder.shouldCache] to an arbitrary JSON value. + * + * You should usually call [Builder.shouldCache] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun shouldCache(shouldCache: JsonField) = apply { body.shouldCache(shouldCache) } + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { body.additionalProperties(additionalBodyProperties) } @@ -352,6 +380,7 @@ private constructor( private val agentConfig: JsonField, private val executeOptions: JsonField, private val frameId: JsonField, + private val shouldCache: JsonField, private val additionalProperties: MutableMap, ) { @@ -364,7 +393,10 @@ private constructor( @ExcludeMissing executeOptions: JsonField = JsonMissing.of(), @JsonProperty("frameId") @ExcludeMissing frameId: JsonField = JsonMissing.of(), - ) : this(agentConfig, executeOptions, frameId, mutableMapOf()) + @JsonProperty("shouldCache") + @ExcludeMissing + shouldCache: JsonField = JsonMissing.of(), + ) : this(agentConfig, executeOptions, frameId, shouldCache, mutableMapOf()) /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is @@ -386,6 +418,14 @@ private constructor( */ fun frameId(): Optional = frameId.getOptional("frameId") + /** + * If true, the server captures a cache entry and returns it to the client + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun shouldCache(): Optional = shouldCache.getOptional("shouldCache") + /** * Returns the raw JSON value of [agentConfig]. * @@ -412,6 +452,15 @@ private constructor( */ @JsonProperty("frameId") @ExcludeMissing fun _frameId(): JsonField = frameId + /** + * Returns the raw JSON value of [shouldCache]. + * + * Unlike [shouldCache], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("shouldCache") + @ExcludeMissing + fun _shouldCache(): JsonField = shouldCache + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -444,6 +493,7 @@ private constructor( private var agentConfig: JsonField? = null private var executeOptions: JsonField? = null private var frameId: JsonField = JsonMissing.of() + private var shouldCache: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -451,6 +501,7 @@ private constructor( agentConfig = body.agentConfig executeOptions = body.executeOptions frameId = body.frameId + shouldCache = body.shouldCache additionalProperties = body.additionalProperties.toMutableMap() } @@ -496,6 +547,20 @@ private constructor( */ fun frameId(frameId: JsonField) = apply { this.frameId = frameId } + /** If true, the server captures a cache entry and returns it to the client */ + fun shouldCache(shouldCache: Boolean) = shouldCache(JsonField.of(shouldCache)) + + /** + * Sets [Builder.shouldCache] to an arbitrary JSON value. + * + * You should usually call [Builder.shouldCache] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun shouldCache(shouldCache: JsonField) = apply { + this.shouldCache = shouldCache + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -533,6 +598,7 @@ private constructor( checkRequired("agentConfig", agentConfig), checkRequired("executeOptions", executeOptions), frameId, + shouldCache, additionalProperties.toMutableMap(), ) } @@ -547,6 +613,7 @@ private constructor( agentConfig().validate() executeOptions().validate() frameId() + shouldCache() validated = true } @@ -568,7 +635,8 @@ private constructor( internal fun validity(): Int = (agentConfig.asKnown().getOrNull()?.validity() ?: 0) + (executeOptions.asKnown().getOrNull()?.validity() ?: 0) + - (if (frameId.asKnown().isPresent) 1 else 0) + (if (frameId.asKnown().isPresent) 1 else 0) + + (if (shouldCache.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -579,17 +647,18 @@ private constructor( agentConfig == other.agentConfig && executeOptions == other.executeOptions && frameId == other.frameId && + shouldCache == other.shouldCache && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(agentConfig, executeOptions, frameId, additionalProperties) + Objects.hash(agentConfig, executeOptions, frameId, shouldCache, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Body{agentConfig=$agentConfig, executeOptions=$executeOptions, frameId=$frameId, additionalProperties=$additionalProperties}" + "Body{agentConfig=$agentConfig, executeOptions=$executeOptions, frameId=$frameId, shouldCache=$shouldCache, additionalProperties=$additionalProperties}" } class AgentConfig diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt index 8718994..8f440d2 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt @@ -195,13 +195,17 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val result: JsonField, + private val cacheEntry: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("result") @ExcludeMissing result: JsonField = JsonMissing.of() - ) : this(result, mutableMapOf()) + @JsonProperty("result") @ExcludeMissing result: JsonField = JsonMissing.of(), + @JsonProperty("cacheEntry") + @ExcludeMissing + cacheEntry: JsonField = JsonMissing.of(), + ) : this(result, cacheEntry, mutableMapOf()) /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is @@ -209,6 +213,12 @@ private constructor( */ fun result(): Result = result.getRequired("result") + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun cacheEntry(): Optional = cacheEntry.getOptional("cacheEntry") + /** * Returns the raw JSON value of [result]. * @@ -216,6 +226,15 @@ private constructor( */ @JsonProperty("result") @ExcludeMissing fun _result(): JsonField = result + /** + * Returns the raw JSON value of [cacheEntry]. + * + * Unlike [cacheEntry], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("cacheEntry") + @ExcludeMissing + fun _cacheEntry(): JsonField = cacheEntry + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -245,11 +264,13 @@ private constructor( class Builder internal constructor() { private var result: JsonField? = null + private var cacheEntry: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(data: Data) = apply { result = data.result + cacheEntry = data.cacheEntry additionalProperties = data.additionalProperties.toMutableMap() } @@ -264,6 +285,19 @@ private constructor( */ fun result(result: JsonField) = apply { this.result = result } + fun cacheEntry(cacheEntry: CacheEntry) = cacheEntry(JsonField.of(cacheEntry)) + + /** + * Sets [Builder.cacheEntry] to an arbitrary JSON value. + * + * You should usually call [Builder.cacheEntry] with a well-typed [CacheEntry] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cacheEntry(cacheEntry: JsonField) = apply { + this.cacheEntry = cacheEntry + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -296,7 +330,11 @@ private constructor( * @throws IllegalStateException if any required field is unset. */ fun build(): Data = - Data(checkRequired("result", result), additionalProperties.toMutableMap()) + Data( + checkRequired("result", result), + cacheEntry, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -307,6 +345,7 @@ private constructor( } result().validate() + cacheEntry().ifPresent { it.validate() } validated = true } @@ -324,7 +363,10 @@ private constructor( * * Used for best match union deserialization. */ - @JvmSynthetic internal fun validity(): Int = (result.asKnown().getOrNull()?.validity() ?: 0) + @JvmSynthetic + internal fun validity(): Int = + (result.asKnown().getOrNull()?.validity() ?: 0) + + (cacheEntry.asKnown().getOrNull()?.validity() ?: 0) class Result @JsonCreator(mode = JsonCreator.Mode.DISABLED) @@ -1621,6 +1663,189 @@ private constructor( "Result{actions=$actions, completed=$completed, message=$message, success=$success, metadata=$metadata, usage=$usage, additionalProperties=$additionalProperties}" } + class CacheEntry + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cacheKey: JsonField, + private val entry: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cacheKey") + @ExcludeMissing + cacheKey: JsonField = JsonMissing.of(), + @JsonProperty("entry") @ExcludeMissing entry: JsonValue = JsonMissing.of(), + ) : this(cacheKey, entry, mutableMapOf()) + + /** + * Opaque cache identifier computed from instruction, URL, options, and config + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun cacheKey(): String = cacheKey.getRequired("cacheKey") + + /** Serialized cache entry that can be written to disk */ + @JsonProperty("entry") @ExcludeMissing fun _entry(): JsonValue = entry + + /** + * Returns the raw JSON value of [cacheKey]. + * + * Unlike [cacheKey], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("cacheKey") @ExcludeMissing fun _cacheKey(): JsonField = cacheKey + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [CacheEntry]. + * + * The following fields are required: + * ```java + * .cacheKey() + * .entry() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [CacheEntry]. */ + class Builder internal constructor() { + + private var cacheKey: JsonField? = null + private var entry: JsonValue? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(cacheEntry: CacheEntry) = apply { + cacheKey = cacheEntry.cacheKey + entry = cacheEntry.entry + additionalProperties = cacheEntry.additionalProperties.toMutableMap() + } + + /** Opaque cache identifier computed from instruction, URL, options, and config */ + fun cacheKey(cacheKey: String) = cacheKey(JsonField.of(cacheKey)) + + /** + * Sets [Builder.cacheKey] to an arbitrary JSON value. + * + * You should usually call [Builder.cacheKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun cacheKey(cacheKey: JsonField) = apply { this.cacheKey = cacheKey } + + /** Serialized cache entry that can be written to disk */ + fun entry(entry: JsonValue) = apply { this.entry = entry } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [CacheEntry]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .cacheKey() + * .entry() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): CacheEntry = + CacheEntry( + checkRequired("cacheKey", cacheKey), + checkRequired("entry", entry), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): CacheEntry = apply { + if (validated) { + return@apply + } + + cacheKey() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (if (cacheKey.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CacheEntry && + cacheKey == other.cacheKey && + entry == other.entry && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(cacheKey, entry, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CacheEntry{cacheKey=$cacheKey, entry=$entry, additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -1628,14 +1853,16 @@ private constructor( return other is Data && result == other.result && + cacheEntry == other.cacheEntry && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(result, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(result, cacheEntry, additionalProperties) } override fun hashCode(): Int = hashCode - override fun toString() = "Data{result=$result, additionalProperties=$additionalProperties}" + override fun toString() = + "Data{result=$result, cacheEntry=$cacheEntry, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 6b4edd1..cfa5176 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -38,6 +38,7 @@ internal class SessionExecuteParamsTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() } @@ -92,6 +93,7 @@ internal class SessionExecuteParamsTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() val headers = params._headers() @@ -150,6 +152,7 @@ internal class SessionExecuteParamsTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() val body = params._body() @@ -181,6 +184,7 @@ internal class SessionExecuteParamsTest { .build() ) assertThat(body.frameId()).contains("frameId") + assertThat(body.shouldCache()).contains(true) } @Test diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt index 85a2099..e88a30e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponseTest.kt @@ -49,6 +49,12 @@ internal class SessionExecuteResponseTest { ) .build() ) + .cacheEntry( + SessionExecuteResponse.Data.CacheEntry.builder() + .cacheKey("cacheKey") + .entry(JsonValue.from(mapOf())) + .build() + ) .build() ) .success(true) @@ -90,6 +96,12 @@ internal class SessionExecuteResponseTest { ) .build() ) + .cacheEntry( + SessionExecuteResponse.Data.CacheEntry.builder() + .cacheKey("cacheKey") + .entry(JsonValue.from(mapOf())) + .build() + ) .build() ) assertThat(sessionExecuteResponse.success()).isEqualTo(true) @@ -135,6 +147,12 @@ internal class SessionExecuteResponseTest { ) .build() ) + .cacheEntry( + SessionExecuteResponse.Data.CacheEntry.builder() + .cacheKey("cacheKey") + .entry(JsonValue.from(mapOf())) + .build() + ) .build() ) .success(true) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index b66ee9e..1a0cd63 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -175,6 +175,7 @@ internal class SessionServiceAsyncTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() ) @@ -224,6 +225,7 @@ internal class SessionServiceAsyncTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index c422457..5a84ee0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -173,6 +173,7 @@ internal class SessionServiceTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() ) @@ -221,6 +222,7 @@ internal class SessionServiceTest { .build() ) .frameId("frameId") + .shouldCache(true) .build() ) From 47a083c53b0b04c8accd59aa91fb01b077a4636e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 03:03:41 +0000 Subject: [PATCH 086/164] feat: add v3 integration tests matching cloud exactly --- .stats.yml | 6 +- .../api/models/sessions/SessionActParams.kt | 201 ++++++++++++++++- .../models/sessions/SessionExecuteParams.kt | 212 +++++++++++++++++- .../models/sessions/SessionExtractParams.kt | 212 +++++++++++++++++- .../models/sessions/SessionObserveParams.kt | 212 +++++++++++++++++- 5 files changed, 800 insertions(+), 43 deletions(-) diff --git a/.stats.yml b/.stats.yml index babf0f2..1e55acc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-2132f9afd90a3b3c35b772f0de3ac8432cfe46ecfa22ec9c1ed4a3d0eda1ad41.yml -openapi_spec_hash: 6da568c2948d8ab6000db4291e15a033 -config_hash: 64c9cc393de93af70e11dbf0b1ba9388 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1c405024b4a17886e921871250a445362463b7ae6070cacc3d1927d59036730c.yml +openapi_spec_hash: c4ea3735257a48ed105002eb7aaa095a +config_hash: 85d56c7c196269badbd0b4a9dfb28d45 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index b8938ca..3445d78 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -773,7 +773,7 @@ private constructor( class Options @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val model: JsonField, + private val model: JsonField, private val timeout: JsonField, private val variables: JsonField, private val additionalProperties: MutableMap, @@ -781,7 +781,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), @JsonProperty("variables") @ExcludeMissing @@ -789,10 +789,12 @@ private constructor( ) : this(model, timeout, variables, mutableMapOf()) /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun model(): Optional = model.getOptional("model") + fun model(): Optional = model.getOptional("model") /** * Timeout in ms for the action @@ -815,7 +817,7 @@ private constructor( * * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model /** * Returns the raw JSON value of [timeout]. @@ -854,7 +856,7 @@ private constructor( /** A builder for [Options]. */ class Builder internal constructor() { - private var model: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() private var timeout: JsonField = JsonMissing.of() private var variables: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -867,16 +869,23 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } - fun model(model: ModelConfig) = model(JsonField.of(model)) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + fun model(model: Model) = model(JsonField.of(model)) /** * Sets [Builder.model] to an arbitrary JSON value. * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.model] with a well-typed [Model] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun model(model: JsonField) = apply { this.model = model } + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `Model.ofConfig(config)`. */ + fun model(config: ModelConfig) = model(Model.ofConfig(config)) + + /** Alias for calling [model] with `Model.ofString(string)`. */ + fun model(string: String) = model(Model.ofString(string)) /** Timeout in ms for the action */ fun timeout(timeout: Double) = timeout(JsonField.of(timeout)) @@ -963,6 +972,178 @@ private constructor( (if (timeout.asKnown().isPresent) 1 else 0) + (variables.asKnown().getOrNull()?.validity() ?: 0) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + @JsonDeserialize(using = Model.Deserializer::class) + @JsonSerialize(using = Model.Serializer::class) + class Model + private constructor( + private val config: ModelConfig? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { + + fun config(): Optional = Optional.ofNullable(config) + + fun string(): Optional = Optional.ofNullable(string) + + fun isConfig(): Boolean = config != null + + fun isString(): Boolean = string != null + + fun asConfig(): ModelConfig = config.getOrThrow("config") + + fun asString(): String = string.getOrThrow("string") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + config != null -> visitor.visitConfig(config) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Model = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) { + config.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) = config.validity() + + override fun visitString(string: String) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Model && config == other.config && string == other.string + } + + override fun hashCode(): Int = Objects.hash(config, string) + + override fun toString(): String = + when { + config != null -> "Model{config=$config}" + string != null -> "Model{string=$string}" + _json != null -> "Model{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Model") + } + + companion object { + + @JvmStatic fun ofConfig(config: ModelConfig) = Model(config = config) + + @JvmStatic fun ofString(string: String) = Model(string = string) + } + + /** + * An interface that defines how to map each variant of [Model] to a value of type [T]. + */ + interface Visitor { + + fun visitConfig(config: ModelConfig): T + + fun visitString(string: String): T + + /** + * Maps an unknown variant of [Model] to a value of type [T]. + * + * An instance of [Model] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Model: $json") + } + } + + internal class Deserializer : BaseDeserializer(Model::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Model { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Model(config = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Model(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from boolean). + 0 -> Model(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Model::class) { + + override fun serialize( + value: Model, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.config != null -> generator.writeObject(value.config) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Model") + } + } + } + } + /** Variables to substitute in the action instruction */ class Variables @JsonCreator diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index c62d819..b5658a5 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -2,13 +2,17 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.errors.StagehandInvalidDataException @@ -16,6 +20,13 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional @@ -665,7 +676,7 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val cua: JsonField, - private val model: JsonField, + private val model: JsonField, private val provider: JsonField, private val systemPrompt: JsonField, private val additionalProperties: MutableMap, @@ -674,7 +685,7 @@ private constructor( @JsonCreator private constructor( @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), @@ -692,10 +703,12 @@ private constructor( fun cua(): Optional = cua.getOptional("cua") /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun model(): Optional = model.getOptional("model") + fun model(): Optional = model.getOptional("model") /** * AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) @@ -725,7 +738,7 @@ private constructor( * * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model /** * Returns the raw JSON value of [provider]. @@ -766,7 +779,7 @@ private constructor( class Builder internal constructor() { private var cua: JsonField = JsonMissing.of() - private var model: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() private var provider: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -792,16 +805,23 @@ private constructor( */ fun cua(cua: JsonField) = apply { this.cua = cua } - fun model(model: ModelConfig) = model(JsonField.of(model)) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + fun model(model: Model) = model(JsonField.of(model)) /** * Sets [Builder.model] to an arbitrary JSON value. * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.model] with a well-typed [Model] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun model(model: JsonField) = apply { this.model = model } + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `Model.ofConfig(config)`. */ + fun model(config: ModelConfig) = model(Model.ofConfig(config)) + + /** Alias for calling [model] with `Model.ofString(string)`. */ + fun model(string: String) = model(Model.ofString(string)) /** AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) */ fun provider(provider: Provider) = provider(JsonField.of(provider)) @@ -892,6 +912,178 @@ private constructor( (provider.asKnown().getOrNull()?.validity() ?: 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + @JsonDeserialize(using = Model.Deserializer::class) + @JsonSerialize(using = Model.Serializer::class) + class Model + private constructor( + private val config: ModelConfig? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { + + fun config(): Optional = Optional.ofNullable(config) + + fun string(): Optional = Optional.ofNullable(string) + + fun isConfig(): Boolean = config != null + + fun isString(): Boolean = string != null + + fun asConfig(): ModelConfig = config.getOrThrow("config") + + fun asString(): String = string.getOrThrow("string") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + config != null -> visitor.visitConfig(config) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Model = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) { + config.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) = config.validity() + + override fun visitString(string: String) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Model && config == other.config && string == other.string + } + + override fun hashCode(): Int = Objects.hash(config, string) + + override fun toString(): String = + when { + config != null -> "Model{config=$config}" + string != null -> "Model{string=$string}" + _json != null -> "Model{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Model") + } + + companion object { + + @JvmStatic fun ofConfig(config: ModelConfig) = Model(config = config) + + @JvmStatic fun ofString(string: String) = Model(string = string) + } + + /** + * An interface that defines how to map each variant of [Model] to a value of type [T]. + */ + interface Visitor { + + fun visitConfig(config: ModelConfig): T + + fun visitString(string: String): T + + /** + * Maps an unknown variant of [Model] to a value of type [T]. + * + * An instance of [Model] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Model: $json") + } + } + + internal class Deserializer : BaseDeserializer(Model::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Model { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Model(config = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Model(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from boolean). + 0 -> Model(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Model::class) { + + override fun serialize( + value: Model, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.config != null -> generator.writeObject(value.config) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Model") + } + } + } + } + /** AI provider for the agent (legacy, use model: openai/gpt-5-nano instead) */ class Provider @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 03cac9e..d732dbe 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -2,12 +2,16 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.toImmutable @@ -16,6 +20,13 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional @@ -612,7 +623,7 @@ private constructor( class Options @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val model: JsonField, + private val model: JsonField, private val selector: JsonField, private val timeout: JsonField, private val additionalProperties: MutableMap, @@ -620,7 +631,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("selector") @ExcludeMissing selector: JsonField = JsonMissing.of(), @@ -628,10 +639,12 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun model(): Optional = model.getOptional("model") + fun model(): Optional = model.getOptional("model") /** * CSS selector to scope extraction to a specific element @@ -654,7 +667,7 @@ private constructor( * * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model /** * Returns the raw JSON value of [selector]. @@ -691,7 +704,7 @@ private constructor( /** A builder for [Options]. */ class Builder internal constructor() { - private var model: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() private var selector: JsonField = JsonMissing.of() private var timeout: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -704,16 +717,23 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } - fun model(model: ModelConfig) = model(JsonField.of(model)) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + fun model(model: Model) = model(JsonField.of(model)) /** * Sets [Builder.model] to an arbitrary JSON value. * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.model] with a well-typed [Model] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun model(model: JsonField) = apply { this.model = model } + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `Model.ofConfig(config)`. */ + fun model(config: ModelConfig) = model(Model.ofConfig(config)) + + /** Alias for calling [model] with `Model.ofString(string)`. */ + fun model(string: String) = model(Model.ofString(string)) /** CSS selector to scope extraction to a specific element */ fun selector(selector: String) = selector(JsonField.of(selector)) @@ -800,6 +820,178 @@ private constructor( (if (selector.asKnown().isPresent) 1 else 0) + (if (timeout.asKnown().isPresent) 1 else 0) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + @JsonDeserialize(using = Model.Deserializer::class) + @JsonSerialize(using = Model.Serializer::class) + class Model + private constructor( + private val config: ModelConfig? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { + + fun config(): Optional = Optional.ofNullable(config) + + fun string(): Optional = Optional.ofNullable(string) + + fun isConfig(): Boolean = config != null + + fun isString(): Boolean = string != null + + fun asConfig(): ModelConfig = config.getOrThrow("config") + + fun asString(): String = string.getOrThrow("string") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + config != null -> visitor.visitConfig(config) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Model = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) { + config.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) = config.validity() + + override fun visitString(string: String) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Model && config == other.config && string == other.string + } + + override fun hashCode(): Int = Objects.hash(config, string) + + override fun toString(): String = + when { + config != null -> "Model{config=$config}" + string != null -> "Model{string=$string}" + _json != null -> "Model{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Model") + } + + companion object { + + @JvmStatic fun ofConfig(config: ModelConfig) = Model(config = config) + + @JvmStatic fun ofString(string: String) = Model(string = string) + } + + /** + * An interface that defines how to map each variant of [Model] to a value of type [T]. + */ + interface Visitor { + + fun visitConfig(config: ModelConfig): T + + fun visitString(string: String): T + + /** + * Maps an unknown variant of [Model] to a value of type [T]. + * + * An instance of [Model] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Model: $json") + } + } + + internal class Deserializer : BaseDeserializer(Model::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Model { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Model(config = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Model(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from boolean). + 0 -> Model(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Model::class) { + + override fun serialize( + value: Model, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.config != null -> generator.writeObject(value.config) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Model") + } + } + } + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 200b881..695025f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -2,12 +2,16 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params +import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams import com.browserbase.api.errors.StagehandInvalidDataException @@ -15,6 +19,13 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional @@ -552,7 +563,7 @@ private constructor( class Options @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val model: JsonField, + private val model: JsonField, private val selector: JsonField, private val timeout: JsonField, private val additionalProperties: MutableMap, @@ -560,7 +571,7 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("selector") @ExcludeMissing selector: JsonField = JsonMissing.of(), @@ -568,10 +579,12 @@ private constructor( ) : this(model, selector, timeout, mutableMapOf()) /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun model(): Optional = model.getOptional("model") + fun model(): Optional = model.getOptional("model") /** * CSS selector to scope observation to a specific element @@ -594,7 +607,7 @@ private constructor( * * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model /** * Returns the raw JSON value of [selector]. @@ -631,7 +644,7 @@ private constructor( /** A builder for [Options]. */ class Builder internal constructor() { - private var model: JsonField = JsonMissing.of() + private var model: JsonField = JsonMissing.of() private var selector: JsonField = JsonMissing.of() private var timeout: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -644,16 +657,23 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } - fun model(model: ModelConfig) = model(JsonField.of(model)) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + fun model(model: Model) = model(JsonField.of(model)) /** * Sets [Builder.model] to an arbitrary JSON value. * - * You should usually call [Builder.model] with a well-typed [ModelConfig] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.model] with a well-typed [Model] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun model(model: JsonField) = apply { this.model = model } + fun model(model: JsonField) = apply { this.model = model } + + /** Alias for calling [model] with `Model.ofConfig(config)`. */ + fun model(config: ModelConfig) = model(Model.ofConfig(config)) + + /** Alias for calling [model] with `Model.ofString(string)`. */ + fun model(string: String) = model(Model.ofString(string)) /** CSS selector to scope observation to a specific element */ fun selector(selector: String) = selector(JsonField.of(selector)) @@ -740,6 +760,178 @@ private constructor( (if (selector.asKnown().isPresent) 1 else 0) + (if (timeout.asKnown().isPresent) 1 else 0) + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ + @JsonDeserialize(using = Model.Deserializer::class) + @JsonSerialize(using = Model.Serializer::class) + class Model + private constructor( + private val config: ModelConfig? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { + + fun config(): Optional = Optional.ofNullable(config) + + fun string(): Optional = Optional.ofNullable(string) + + fun isConfig(): Boolean = config != null + + fun isString(): Boolean = string != null + + fun asConfig(): ModelConfig = config.getOrThrow("config") + + fun asString(): String = string.getOrThrow("string") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + config != null -> visitor.visitConfig(config) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Model = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) { + config.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitConfig(config: ModelConfig) = config.validity() + + override fun visitString(string: String) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Model && config == other.config && string == other.string + } + + override fun hashCode(): Int = Objects.hash(config, string) + + override fun toString(): String = + when { + config != null -> "Model{config=$config}" + string != null -> "Model{string=$string}" + _json != null -> "Model{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Model") + } + + companion object { + + @JvmStatic fun ofConfig(config: ModelConfig) = Model(config = config) + + @JvmStatic fun ofString(string: String) = Model(string = string) + } + + /** + * An interface that defines how to map each variant of [Model] to a value of type [T]. + */ + interface Visitor { + + fun visitConfig(config: ModelConfig): T + + fun visitString(string: String): T + + /** + * Maps an unknown variant of [Model] to a value of type [T]. + * + * An instance of [Model] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown Model: $json") + } + } + + internal class Deserializer : BaseDeserializer(Model::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Model { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Model(config = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Model(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from boolean). + 0 -> Model(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Model::class) { + + override fun serialize( + value: Model, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.config != null -> generator.writeObject(value.config) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Model") + } + } + } + } + override fun equals(other: Any?): Boolean { if (this === other) { return true From 1e1a6d8b3ab1d1bba3db39889a1785c03f11a96e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 01:12:24 +0000 Subject: [PATCH 087/164] feat: Include replay endpoint in stainless spec so SDK clients can get run metrics --- .stats.yml | 8 +- .../models/sessions/SessionReplayParams.kt | 355 ++++++ .../models/sessions/SessionReplayResponse.kt | 1053 +++++++++++++++++ .../api/services/async/SessionServiceAsync.kt | 78 ++ .../services/async/SessionServiceAsyncImpl.kt | 42 + .../api/services/blocking/SessionService.kt | 76 ++ .../services/blocking/SessionServiceImpl.kt | 39 + .../sessions/SessionReplayParamsTest.kt | 51 + .../sessions/SessionReplayResponseTest.kt | 107 ++ .../services/async/SessionServiceAsyncTest.kt | 25 + .../services/blocking/SessionServiceTest.kt | 24 + 11 files changed, 1854 insertions(+), 4 deletions(-) create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayParamsTest.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt diff --git a/.stats.yml b/.stats.yml index 1e55acc..094239e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 7 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1c405024b4a17886e921871250a445362463b7ae6070cacc3d1927d59036730c.yml -openapi_spec_hash: c4ea3735257a48ed105002eb7aaa095a -config_hash: 85d56c7c196269badbd0b4a9dfb28d45 +configured_endpoints: 8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-089c8670f1d7c2e9fa8e5c97010db7c24b8f162eb7cfe76ffa41d70fa46efe2f.yml +openapi_spec_hash: 7a226aee8f3f2ab16febbe6bb35e1657 +config_hash: 8e4ed6629c178aa0c8aaf575cb07c544 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt new file mode 100644 index 0000000..093a776 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt @@ -0,0 +1,355 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.Enum +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.Params +import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonCreator +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Retrieves replay metrics for a session. */ +class SessionReplayParams +private constructor( + private val id: String?, + private val xStreamResponse: XStreamResponse?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** Unique session identifier */ + fun id(): Optional = Optional.ofNullable(id) + + /** Whether to stream the response via SSE */ + fun xStreamResponse(): Optional = Optional.ofNullable(xStreamResponse) + + /** Additional headers to send with the request. */ + fun _additionalHeaders(): Headers = additionalHeaders + + /** Additional query param to send with the request. */ + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): SessionReplayParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [SessionReplayParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionReplayParams]. */ + class Builder internal constructor() { + + private var id: String? = null + private var xStreamResponse: XStreamResponse? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(sessionReplayParams: SessionReplayParams) = apply { + id = sessionReplayParams.id + xStreamResponse = sessionReplayParams.xStreamResponse + additionalHeaders = sessionReplayParams.additionalHeaders.toBuilder() + additionalQueryParams = sessionReplayParams.additionalQueryParams.toBuilder() + } + + /** Unique session identifier */ + fun id(id: String?) = apply { this.id = id } + + /** Alias for calling [Builder.id] with `id.orElse(null)`. */ + fun id(id: Optional) = id(id.getOrNull()) + + /** Whether to stream the response via SSE */ + fun xStreamResponse(xStreamResponse: XStreamResponse?) = apply { + this.xStreamResponse = xStreamResponse + } + + /** Alias for calling [Builder.xStreamResponse] with `xStreamResponse.orElse(null)`. */ + fun xStreamResponse(xStreamResponse: Optional) = + xStreamResponse(xStreamResponse.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [SessionReplayParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SessionReplayParams = + SessionReplayParams( + id, + xStreamResponse, + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _pathParam(index: Int): String = + when (index) { + 0 -> id ?: "" + else -> "" + } + + override fun _headers(): Headers = + Headers.builder() + .apply { + xStreamResponse?.let { put("x-stream-response", it.toString()) } + putAll(additionalHeaders) + } + .build() + + override fun _queryParams(): QueryParams = additionalQueryParams + + /** Whether to stream the response via SSE */ + class XStreamResponse @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val TRUE = of("true") + + @JvmField val FALSE = of("false") + + @JvmStatic fun of(value: String) = XStreamResponse(JsonField.of(value)) + } + + /** An enum containing [XStreamResponse]'s known values. */ + enum class Known { + TRUE, + FALSE, + } + + /** + * An enum containing [XStreamResponse]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [XStreamResponse] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + TRUE, + FALSE, + /** + * An enum member indicating that [XStreamResponse] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + TRUE -> Value.TRUE + FALSE -> Value.FALSE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + TRUE -> Known.TRUE + FALSE -> Known.FALSE + else -> throw StagehandInvalidDataException("Unknown XStreamResponse: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): XStreamResponse = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XStreamResponse && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionReplayParams && + id == other.id && + xStreamResponse == other.xStreamResponse && + additionalHeaders == other.additionalHeaders && + additionalQueryParams == other.additionalQueryParams + } + + override fun hashCode(): Int = + Objects.hash(id, xStreamResponse, additionalHeaders, additionalQueryParams) + + override fun toString() = + "SessionReplayParams{id=$id, xStreamResponse=$xStreamResponse, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt new file mode 100644 index 0000000..39ecafa --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt @@ -0,0 +1,1053 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.ExcludeMissing +import com.browserbase.api.core.JsonField +import com.browserbase.api.core.JsonMissing +import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.checkKnown +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable +import com.browserbase.api.errors.StagehandInvalidDataException +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class SessionReplayResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val data: JsonField, + private val success: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("data") @ExcludeMissing data: JsonField = JsonMissing.of(), + @JsonProperty("success") @ExcludeMissing success: JsonField = JsonMissing.of(), + ) : this(data, success, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun data(): Data = data.getRequired("data") + + /** + * Indicates whether the request was successful + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun success(): Boolean = success.getRequired("success") + + /** + * Returns the raw JSON value of [data]. + * + * Unlike [data], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("data") @ExcludeMissing fun _data(): JsonField = data + + /** + * Returns the raw JSON value of [success]. + * + * Unlike [success], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("success") @ExcludeMissing fun _success(): JsonField = success + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SessionReplayResponse]. + * + * The following fields are required: + * ```java + * .data() + * .success() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SessionReplayResponse]. */ + class Builder internal constructor() { + + private var data: JsonField? = null + private var success: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sessionReplayResponse: SessionReplayResponse) = apply { + data = sessionReplayResponse.data + success = sessionReplayResponse.success + additionalProperties = sessionReplayResponse.additionalProperties.toMutableMap() + } + + fun data(data: Data) = data(JsonField.of(data)) + + /** + * Sets [Builder.data] to an arbitrary JSON value. + * + * You should usually call [Builder.data] with a well-typed [Data] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun data(data: JsonField) = apply { this.data = data } + + /** Indicates whether the request was successful */ + fun success(success: Boolean) = success(JsonField.of(success)) + + /** + * Sets [Builder.success] to an arbitrary JSON value. + * + * You should usually call [Builder.success] with a well-typed [Boolean] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun success(success: JsonField) = apply { this.success = success } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SessionReplayResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .data() + * .success() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SessionReplayResponse = + SessionReplayResponse( + checkRequired("data", data), + checkRequired("success", success), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SessionReplayResponse = apply { + if (validated) { + return@apply + } + + data().validate() + success() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (data.asKnown().getOrNull()?.validity() ?: 0) + (if (success.asKnown().isPresent) 1 else 0) + + class Data + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val pages: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("pages") @ExcludeMissing pages: JsonField> = JsonMissing.of() + ) : this(pages, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pages(): Optional> = pages.getOptional("pages") + + /** + * Returns the raw JSON value of [pages]. + * + * Unlike [pages], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pages") @ExcludeMissing fun _pages(): JsonField> = pages + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Data]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Data]. */ + class Builder internal constructor() { + + private var pages: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(data: Data) = apply { + pages = data.pages.map { it.toMutableList() } + additionalProperties = data.additionalProperties.toMutableMap() + } + + fun pages(pages: List) = pages(JsonField.of(pages)) + + /** + * Sets [Builder.pages] to an arbitrary JSON value. + * + * You should usually call [Builder.pages] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pages(pages: JsonField>) = apply { + this.pages = pages.map { it.toMutableList() } + } + + /** + * Adds a single [Page] to [pages]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addPage(page: Page) = apply { + pages = + (pages ?: JsonField.of(mutableListOf())).also { + checkKnown("pages", it).add(page) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Data]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Data = + Data( + (pages ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Data = apply { + if (validated) { + return@apply + } + + pages().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (pages.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + class Page + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val actions: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("actions") + @ExcludeMissing + actions: JsonField> = JsonMissing.of() + ) : this(actions, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun actions(): Optional> = actions.getOptional("actions") + + /** + * Returns the raw JSON value of [actions]. + * + * Unlike [actions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("actions") + @ExcludeMissing + fun _actions(): JsonField> = actions + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Page]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Page]. */ + class Builder internal constructor() { + + private var actions: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(page: Page) = apply { + actions = page.actions.map { it.toMutableList() } + additionalProperties = page.additionalProperties.toMutableMap() + } + + fun actions(actions: List) = actions(JsonField.of(actions)) + + /** + * Sets [Builder.actions] to an arbitrary JSON value. + * + * You should usually call [Builder.actions] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun actions(actions: JsonField>) = apply { + this.actions = actions.map { it.toMutableList() } + } + + /** + * Adds a single [Action] to [actions]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addAction(action: Action) = apply { + actions = + (actions ?: JsonField.of(mutableListOf())).also { + checkKnown("actions", it).add(action) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Page]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Page = + Page( + (actions ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Page = apply { + if (validated) { + return@apply + } + + actions().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + class Action + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val method: JsonField, + private val tokenUsage: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("method") + @ExcludeMissing + method: JsonField = JsonMissing.of(), + @JsonProperty("tokenUsage") + @ExcludeMissing + tokenUsage: JsonField = JsonMissing.of(), + ) : this(method, tokenUsage, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun method(): Optional = method.getOptional("method") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun tokenUsage(): Optional = tokenUsage.getOptional("tokenUsage") + + /** + * Returns the raw JSON value of [method]. + * + * Unlike [method], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + + /** + * Returns the raw JSON value of [tokenUsage]. + * + * Unlike [tokenUsage], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("tokenUsage") + @ExcludeMissing + fun _tokenUsage(): JsonField = tokenUsage + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Action]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Action]. */ + class Builder internal constructor() { + + private var method: JsonField = JsonMissing.of() + private var tokenUsage: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(action: Action) = apply { + method = action.method + tokenUsage = action.tokenUsage + additionalProperties = action.additionalProperties.toMutableMap() + } + + fun method(method: String) = method(JsonField.of(method)) + + /** + * Sets [Builder.method] to an arbitrary JSON value. + * + * You should usually call [Builder.method] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun method(method: JsonField) = apply { this.method = method } + + fun tokenUsage(tokenUsage: TokenUsage) = tokenUsage(JsonField.of(tokenUsage)) + + /** + * Sets [Builder.tokenUsage] to an arbitrary JSON value. + * + * You should usually call [Builder.tokenUsage] with a well-typed [TokenUsage] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun tokenUsage(tokenUsage: JsonField) = apply { + this.tokenUsage = tokenUsage + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Action]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Action = + Action(method, tokenUsage, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Action = apply { + if (validated) { + return@apply + } + + method() + tokenUsage().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (method.asKnown().isPresent) 1 else 0) + + (tokenUsage.asKnown().getOrNull()?.validity() ?: 0) + + class TokenUsage + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val cachedInputTokens: JsonField, + private val inputTokens: JsonField, + private val outputTokens: JsonField, + private val reasoningTokens: JsonField, + private val timeMs: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("cachedInputTokens") + @ExcludeMissing + cachedInputTokens: JsonField = JsonMissing.of(), + @JsonProperty("inputTokens") + @ExcludeMissing + inputTokens: JsonField = JsonMissing.of(), + @JsonProperty("outputTokens") + @ExcludeMissing + outputTokens: JsonField = JsonMissing.of(), + @JsonProperty("reasoningTokens") + @ExcludeMissing + reasoningTokens: JsonField = JsonMissing.of(), + @JsonProperty("timeMs") + @ExcludeMissing + timeMs: JsonField = JsonMissing.of(), + ) : this( + cachedInputTokens, + inputTokens, + outputTokens, + reasoningTokens, + timeMs, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun cachedInputTokens(): Optional = + cachedInputTokens.getOptional("cachedInputTokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun inputTokens(): Optional = inputTokens.getOptional("inputTokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun outputTokens(): Optional = outputTokens.getOptional("outputTokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun reasoningTokens(): Optional = + reasoningTokens.getOptional("reasoningTokens") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun timeMs(): Optional = timeMs.getOptional("timeMs") + + /** + * Returns the raw JSON value of [cachedInputTokens]. + * + * Unlike [cachedInputTokens], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("cachedInputTokens") + @ExcludeMissing + fun _cachedInputTokens(): JsonField = cachedInputTokens + + /** + * Returns the raw JSON value of [inputTokens]. + * + * Unlike [inputTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("inputTokens") + @ExcludeMissing + fun _inputTokens(): JsonField = inputTokens + + /** + * Returns the raw JSON value of [outputTokens]. + * + * Unlike [outputTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("outputTokens") + @ExcludeMissing + fun _outputTokens(): JsonField = outputTokens + + /** + * Returns the raw JSON value of [reasoningTokens]. + * + * Unlike [reasoningTokens], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("reasoningTokens") + @ExcludeMissing + fun _reasoningTokens(): JsonField = reasoningTokens + + /** + * Returns the raw JSON value of [timeMs]. + * + * Unlike [timeMs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("timeMs") + @ExcludeMissing + fun _timeMs(): JsonField = timeMs + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [TokenUsage]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [TokenUsage]. */ + class Builder internal constructor() { + + private var cachedInputTokens: JsonField = JsonMissing.of() + private var inputTokens: JsonField = JsonMissing.of() + private var outputTokens: JsonField = JsonMissing.of() + private var reasoningTokens: JsonField = JsonMissing.of() + private var timeMs: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(tokenUsage: TokenUsage) = apply { + cachedInputTokens = tokenUsage.cachedInputTokens + inputTokens = tokenUsage.inputTokens + outputTokens = tokenUsage.outputTokens + reasoningTokens = tokenUsage.reasoningTokens + timeMs = tokenUsage.timeMs + additionalProperties = tokenUsage.additionalProperties.toMutableMap() + } + + fun cachedInputTokens(cachedInputTokens: Double) = + cachedInputTokens(JsonField.of(cachedInputTokens)) + + /** + * Sets [Builder.cachedInputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.cachedInputTokens] with a well-typed + * [Double] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun cachedInputTokens(cachedInputTokens: JsonField) = apply { + this.cachedInputTokens = cachedInputTokens + } + + fun inputTokens(inputTokens: Double) = + inputTokens(JsonField.of(inputTokens)) + + /** + * Sets [Builder.inputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.inputTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun inputTokens(inputTokens: JsonField) = apply { + this.inputTokens = inputTokens + } + + fun outputTokens(outputTokens: Double) = + outputTokens(JsonField.of(outputTokens)) + + /** + * Sets [Builder.outputTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.outputTokens] with a well-typed [Double] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun outputTokens(outputTokens: JsonField) = apply { + this.outputTokens = outputTokens + } + + fun reasoningTokens(reasoningTokens: Double) = + reasoningTokens(JsonField.of(reasoningTokens)) + + /** + * Sets [Builder.reasoningTokens] to an arbitrary JSON value. + * + * You should usually call [Builder.reasoningTokens] with a well-typed + * [Double] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun reasoningTokens(reasoningTokens: JsonField) = apply { + this.reasoningTokens = reasoningTokens + } + + fun timeMs(timeMs: Double) = timeMs(JsonField.of(timeMs)) + + /** + * Sets [Builder.timeMs] to an arbitrary JSON value. + * + * You should usually call [Builder.timeMs] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun timeMs(timeMs: JsonField) = apply { this.timeMs = timeMs } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [TokenUsage]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): TokenUsage = + TokenUsage( + cachedInputTokens, + inputTokens, + outputTokens, + reasoningTokens, + timeMs, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): TokenUsage = apply { + if (validated) { + return@apply + } + + cachedInputTokens() + inputTokens() + outputTokens() + reasoningTokens() + timeMs() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (cachedInputTokens.asKnown().isPresent) 1 else 0) + + (if (inputTokens.asKnown().isPresent) 1 else 0) + + (if (outputTokens.asKnown().isPresent) 1 else 0) + + (if (reasoningTokens.asKnown().isPresent) 1 else 0) + + (if (timeMs.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is TokenUsage && + cachedInputTokens == other.cachedInputTokens && + inputTokens == other.inputTokens && + outputTokens == other.outputTokens && + reasoningTokens == other.reasoningTokens && + timeMs == other.timeMs && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + cachedInputTokens, + inputTokens, + outputTokens, + reasoningTokens, + timeMs, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "TokenUsage{cachedInputTokens=$cachedInputTokens, inputTokens=$inputTokens, outputTokens=$outputTokens, reasoningTokens=$reasoningTokens, timeMs=$timeMs, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Action && + method == other.method && + tokenUsage == other.tokenUsage && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(method, tokenUsage, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Action{method=$method, tokenUsage=$tokenUsage, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Page && + actions == other.actions && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(actions, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Page{actions=$actions, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Data && + pages == other.pages && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(pages, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Data{pages=$pages, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SessionReplayResponse && + data == other.data && + success == other.success && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(data, success, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SessionReplayResponse{data=$data, success=$success, additionalProperties=$additionalProperties}" +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt index 5c9171e..f9e65e6 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsync.kt @@ -19,6 +19,8 @@ import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionNavigateResponse import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse +import com.browserbase.api.models.sessions.SessionReplayParams +import com.browserbase.api.models.sessions.SessionReplayResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import com.browserbase.api.models.sessions.StreamEvent @@ -337,6 +339,41 @@ interface SessionServiceAsync { ): AsyncStreamResponse = observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** Retrieves replay metrics for a session. */ + fun replay(id: String): CompletableFuture = + replay(id, SessionReplayParams.none()) + + /** @see replay */ + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + replay(params.toBuilder().id(id).build(), requestOptions) + + /** @see replay */ + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + ): CompletableFuture = replay(id, params, RequestOptions.none()) + + /** @see replay */ + fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see replay */ + fun replay(params: SessionReplayParams): CompletableFuture = + replay(params, RequestOptions.none()) + + /** @see replay */ + fun replay( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = + replay(id, SessionReplayParams.none(), requestOptions) + /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. @@ -739,6 +776,47 @@ interface SessionServiceAsync { ): CompletableFuture>> = observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** + * Returns a raw HTTP response for `get /v1/sessions/{id}/replay`, but is otherwise the same + * as [SessionServiceAsync.replay]. + */ + fun replay(id: String): CompletableFuture> = + replay(id, SessionReplayParams.none()) + + /** @see replay */ + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + replay(params.toBuilder().id(id).build(), requestOptions) + + /** @see replay */ + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + ): CompletableFuture> = + replay(id, params, RequestOptions.none()) + + /** @see replay */ + fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see replay */ + fun replay( + params: SessionReplayParams + ): CompletableFuture> = + replay(params, RequestOptions.none()) + + /** @see replay */ + fun replay( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + replay(id, SessionReplayParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/start`, but is otherwise the same as * [SessionServiceAsync.start]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 82062e4..7652220 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -35,6 +35,8 @@ import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionNavigateResponse import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse +import com.browserbase.api.models.sessions.SessionReplayParams +import com.browserbase.api.models.sessions.SessionReplayResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import com.browserbase.api.models.sessions.StreamEvent @@ -136,6 +138,13 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .thenApply { it.parse() } .toAsync(clientOptions.streamHandlerExecutor) + override fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // get /v1/sessions/{id}/replay + withRawResponse().replay(params, requestOptions).thenApply { it.parse() } + override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -540,6 +549,39 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl } } + private val replayHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "replay") + .build() + .prepareAsync(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + errorHandler.handle(response).parseable { + response + .use { replayHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt index 0d56e93..1c44d08 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionService.kt @@ -18,6 +18,8 @@ import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionNavigateResponse import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse +import com.browserbase.api.models.sessions.SessionReplayParams +import com.browserbase.api.models.sessions.SessionReplayResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import com.browserbase.api.models.sessions.StreamEvent @@ -324,6 +326,36 @@ interface SessionService { fun observeStreaming(id: String, requestOptions: RequestOptions): StreamResponse = observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** Retrieves replay metrics for a session. */ + fun replay(id: String): SessionReplayResponse = replay(id, SessionReplayParams.none()) + + /** @see replay */ + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionReplayResponse = replay(params.toBuilder().id(id).build(), requestOptions) + + /** @see replay */ + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + ): SessionReplayResponse = replay(id, params, RequestOptions.none()) + + /** @see replay */ + fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): SessionReplayResponse + + /** @see replay */ + fun replay(params: SessionReplayParams): SessionReplayResponse = + replay(params, RequestOptions.none()) + + /** @see replay */ + fun replay(id: String, requestOptions: RequestOptions): SessionReplayResponse = + replay(id, SessionReplayParams.none(), requestOptions) + /** * Creates a new browser session with the specified configuration. Returns a session ID used for * all subsequent operations. @@ -726,6 +758,50 @@ interface SessionService { ): HttpResponseFor> = observeStreaming(id, SessionObserveParams.none(), requestOptions) + /** + * Returns a raw HTTP response for `get /v1/sessions/{id}/replay`, but is otherwise the same + * as [SessionService.replay]. + */ + @MustBeClosed + fun replay(id: String): HttpResponseFor = + replay(id, SessionReplayParams.none()) + + /** @see replay */ + @MustBeClosed + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + replay(params.toBuilder().id(id).build(), requestOptions) + + /** @see replay */ + @MustBeClosed + fun replay( + id: String, + params: SessionReplayParams = SessionReplayParams.none(), + ): HttpResponseFor = replay(id, params, RequestOptions.none()) + + /** @see replay */ + @MustBeClosed + fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see replay */ + @MustBeClosed + fun replay(params: SessionReplayParams): HttpResponseFor = + replay(params, RequestOptions.none()) + + /** @see replay */ + @MustBeClosed + fun replay( + id: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + replay(id, SessionReplayParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /v1/sessions/start`, but is otherwise the same as * [SessionService.start]. diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index 4bfce1b..35a7856 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -33,6 +33,8 @@ import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionNavigateResponse import com.browserbase.api.models.sessions.SessionObserveParams import com.browserbase.api.models.sessions.SessionObserveResponse +import com.browserbase.api.models.sessions.SessionReplayParams +import com.browserbase.api.models.sessions.SessionReplayResponse import com.browserbase.api.models.sessions.SessionStartParams import com.browserbase.api.models.sessions.SessionStartResponse import com.browserbase.api.models.sessions.StreamEvent @@ -115,6 +117,13 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO // post /v1/sessions/{id}/observe withRawResponse().observeStreaming(params, requestOptions).parse() + override fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions, + ): SessionReplayResponse = + // get /v1/sessions/{id}/replay + withRawResponse().replay(params, requestOptions).parse() + override fun start( params: SessionStartParams, requestOptions: RequestOptions, @@ -489,6 +498,36 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO } } + private val replayHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + + override fun replay( + params: SessionReplayParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("id", params.id().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl(clientOptions.baseUrl()) + .addPathSegments("v1", "sessions", params._pathParam(0), "replay") + .build() + .prepare(clientOptions, params) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return errorHandler.handle(response).parseable { + response + .use { replayHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + private val startHandler: Handler = jsonHandler(clientOptions.jsonMapper) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayParamsTest.kt new file mode 100644 index 0000000..7bef35a --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayParamsTest.kt @@ -0,0 +1,51 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.http.Headers +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionReplayParamsTest { + + @Test + fun create() { + SessionReplayParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xStreamResponse(SessionReplayParams.XStreamResponse.TRUE) + .build() + } + + @Test + fun pathParams() { + val params = + SessionReplayParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() + + assertThat(params._pathParam(0)).isEqualTo("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } + + @Test + fun headers() { + val params = + SessionReplayParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xStreamResponse(SessionReplayParams.XStreamResponse.TRUE) + .build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().put("x-stream-response", "true").build()) + } + + @Test + fun headersWithoutOptionalFields() { + val params = + SessionReplayParams.builder().id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123").build() + + val headers = params._headers() + + assertThat(headers).isEqualTo(Headers.builder().build()) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt new file mode 100644 index 0000000..848c7f7 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt @@ -0,0 +1,107 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.models.sessions + +import com.browserbase.api.core.jsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SessionReplayResponseTest { + + @Test + fun create() { + val sessionReplayResponse = + SessionReplayResponse.builder() + .data( + SessionReplayResponse.Data.builder() + .addPage( + SessionReplayResponse.Data.Page.builder() + .addAction( + SessionReplayResponse.Data.Page.Action.builder() + .method("method") + .tokenUsage( + SessionReplayResponse.Data.Page.Action.TokenUsage + .builder() + .cachedInputTokens(0.0) + .inputTokens(0.0) + .outputTokens(0.0) + .reasoningTokens(0.0) + .timeMs(0.0) + .build() + ) + .build() + ) + .build() + ) + .build() + ) + .success(true) + .build() + + assertThat(sessionReplayResponse.data()) + .isEqualTo( + SessionReplayResponse.Data.builder() + .addPage( + SessionReplayResponse.Data.Page.builder() + .addAction( + SessionReplayResponse.Data.Page.Action.builder() + .method("method") + .tokenUsage( + SessionReplayResponse.Data.Page.Action.TokenUsage.builder() + .cachedInputTokens(0.0) + .inputTokens(0.0) + .outputTokens(0.0) + .reasoningTokens(0.0) + .timeMs(0.0) + .build() + ) + .build() + ) + .build() + ) + .build() + ) + assertThat(sessionReplayResponse.success()).isEqualTo(true) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val sessionReplayResponse = + SessionReplayResponse.builder() + .data( + SessionReplayResponse.Data.builder() + .addPage( + SessionReplayResponse.Data.Page.builder() + .addAction( + SessionReplayResponse.Data.Page.Action.builder() + .method("method") + .tokenUsage( + SessionReplayResponse.Data.Page.Action.TokenUsage + .builder() + .cachedInputTokens(0.0) + .inputTokens(0.0) + .outputTokens(0.0) + .reasoningTokens(0.0) + .timeMs(0.0) + .build() + ) + .build() + ) + .build() + ) + .build() + ) + .success(true) + .build() + + val roundtrippedSessionReplayResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(sessionReplayResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSessionReplayResponse).isEqualTo(sessionReplayResponse) + } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 1a0cd63..42eb483 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -12,6 +12,7 @@ import com.browserbase.api.models.sessions.SessionExecuteParams import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionReplayParams import com.browserbase.api.models.sessions.SessionStartParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -440,6 +441,30 @@ internal class SessionServiceAsyncTest { onCompleteFuture.get() } + @Disabled("Prism tests are disabled") + @Test + fun replay() { + val client = + StagehandOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionServiceAsync = client.sessions() + + val responseFuture = + sessionServiceAsync.replay( + SessionReplayParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xStreamResponse(SessionReplayParams.XStreamResponse.TRUE) + .build() + ) + + val response = responseFuture.get() + response.validate() + } + @Disabled("Prism tests are disabled") @Test fun start() { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 5a84ee0..8b05e95 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -12,6 +12,7 @@ import com.browserbase.api.models.sessions.SessionExecuteParams import com.browserbase.api.models.sessions.SessionExtractParams import com.browserbase.api.models.sessions.SessionNavigateParams import com.browserbase.api.models.sessions.SessionObserveParams +import com.browserbase.api.models.sessions.SessionReplayParams import com.browserbase.api.models.sessions.SessionStartParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test @@ -434,6 +435,29 @@ internal class SessionServiceTest { } } + @Disabled("Prism tests are disabled") + @Test + fun replay() { + val client = + StagehandOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + val sessionService = client.sessions() + + val response = + sessionService.replay( + SessionReplayParams.builder() + .id("c4dbf3a9-9a58-4b22-8a1c-9f20f9f9e123") + .xStreamResponse(SessionReplayParams.XStreamResponse.TRUE) + .build() + ) + + response.validate() + } + @Disabled("Prism tests are disabled") @Test fun start() { From c627921bfd1b68c66b8438af58c9fee3b41fdc6d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 04:08:36 +0000 Subject: [PATCH 088/164] chore(internal): update maven repo doc to include authentication --- scripts/upload-artifacts | 64 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/scripts/upload-artifacts b/scripts/upload-artifacts index 548d152..10f3c70 100755 --- a/scripts/upload-artifacts +++ b/scripts/upload-artifacts @@ -96,8 +96,52 @@ generate_instructions() {

Stainless SDK Maven Repository

This is the Maven repository for your Stainless Java SDK build.

-

Directions

-

To use the uploaded Maven repository, add the following to your project's pom.xml:

+

Project configuration

+ +

The details depend on whether you're using Maven or Gradle as your build tool.

+ +

Maven

+ +

Add the following to your project's pom.xml:

+
<repositories>
+    <repository>
+        <id>stainless-sdk-repo</id>
+        <url>https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn</url>
+    </repository>
+</repositories>
+ +

Gradle

+

Add the following to your build.gradle file:

+
repositories {
+    maven {
+        url "https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn"
+    }
+}
+ +
+

Configuring authentication (if required)

+ +

Some accounts may require authentication to access the repository. If so, use the + following instructions, replacing YOUR_STAINLESS_API_TOKEN with your actual token.

+ +

Maven with authentication

+ +

First, ensure you have the following in your Maven settings.xml for repo authentication:

+
<servers>
+    <server>
+        <id>stainless-sdk-repo</id>
+        <configuration>
+            <httpHeaders>
+                <property>
+                    <name>Authorization</name>
+                    <value>Bearer YOUR_STAINLESS_API_TOKEN</value>
+                </property>
+            </httpHeaders>
+        </configuration>
+    </server>
+</servers>
+ +

Then, add the following to your project's pom.xml:

<repositories>
     <repository>
         <id>stainless-sdk-repo</id>
@@ -105,14 +149,24 @@ generate_instructions() {
     </repository>
 </repositories>
-

If you're using Gradle, add the following to your build.gradle file:

+

Gradle with authentication

+

Add the following to your build.gradle file:

repositories {
     maven {
-        url 'https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn'
+        url "https://pkg.stainless.com/s/${PROJECT}/${SHA}/mvn"
+        credentials(HttpHeaderCredentials) {
+            name = "Authorization"
+            value = "Bearer YOUR_STAINLESS_API_TOKEN"
+        }
+        authentication {
+            header(HttpHeaderAuthentication)
+        }
     }
 }
+
-

Once you've added the repository, you can include dependencies from it as usual. See your +

Using the repository

+

Once you've configured the repository, you can include dependencies from it as usual. See your project README for more details.

From 9b90e6c75452e6bd1e3bd57bc07cc3f7dd7f2c64 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 04:09:48 +0000 Subject: [PATCH 089/164] feat(client): send `X-Stainless-Kotlin-Version` header --- .../src/main/kotlin/com/browserbase/api/core/ClientOptions.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 732c468..8b1c7f0 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -484,6 +484,7 @@ private constructor( headers.put("X-Stainless-Package-Version", getPackageVersion()) headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) + headers.put("X-Stainless-Kotlin-Version", KotlinVersion.CURRENT.toString()) browserbaseApiKey.let { if (!it.isEmpty()) { headers.put("x-bb-api-key", it) From 0b3ef6e020b36ded3b0fbce4cde6d54653edbb29 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:18:42 +0000 Subject: [PATCH 090/164] docs: add comment for arbitrary value fields --- .../api/models/sessions/SessionExecuteResponse.kt | 10 +++++++++- .../api/models/sessions/SessionExtractResponse.kt | 9 ++++++++- .../api/models/sessions/SessionNavigateResponse.kt | 9 ++++++++- .../com/browserbase/api/models/sessions/StreamEvent.kt | 10 +++++++++- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt index 8f440d2..9b16655 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt @@ -1688,7 +1688,15 @@ private constructor( */ fun cacheKey(): String = cacheKey.getRequired("cacheKey") - /** Serialized cache entry that can be written to disk */ + /** + * Serialized cache entry that can be written to disk + * + * This arbitrary value can be deserialized into a custom type using the `convert` + * method: + * ```java + * MyClass myObject = cacheEntry.entry().convert(MyClass.class); + * ``` + */ @JsonProperty("entry") @ExcludeMissing fun _entry(): JsonValue = entry /** diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index e281560..306abcd 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -203,7 +203,14 @@ private constructor( @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), ) : this(result, actionId, mutableMapOf()) - /** Extracted data matching the requested schema */ + /** + * Extracted data matching the requested schema + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = data.result().convert(MyClass.class); + * ``` + */ @JsonProperty("result") @ExcludeMissing fun _result(): JsonValue = result /** diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt index 2518477..1f6e688 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -203,7 +203,14 @@ private constructor( @JsonProperty("actionId") @ExcludeMissing actionId: JsonField = JsonMissing.of(), ) : this(result, actionId, mutableMapOf()) - /** Navigation response (Playwright Response object or null) */ + /** + * Navigation response (Playwright Response object or null) + * + * This arbitrary value can be deserialized into a custom type using the `convert` method: + * ```java + * MyClass myObject = data.result().convert(MyClass.class); + * ``` + */ @JsonProperty("result") @ExcludeMissing fun _result(): JsonValue = result /** diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt index a123e6a..443104b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -486,7 +486,15 @@ private constructor( */ fun error(): Optional = error.getOptional("error") - /** Operation result (present when status is 'finished') */ + /** + * Operation result (present when status is 'finished') + * + * This arbitrary value can be deserialized into a custom type using the `convert` + * method: + * ```java + * MyClass myObject = streamEventSystemDataOutput.result().convert(MyClass.class); + * ``` + */ @JsonProperty("result") @ExcludeMissing fun _result(): JsonValue = result /** From 58a3b5cd9535defde79115fd4c4d6de24614a674 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:19:37 +0000 Subject: [PATCH 091/164] chore(internal): correct cache invalidation for `SKIP_MOCK_TESTS` --- buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts index f3f48d1..be6cf65 100644 --- a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts @@ -33,6 +33,9 @@ kotlin { tasks.withType().configureEach { systemProperty("junit.jupiter.execution.parallel.enabled", true) systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent") + + // `SKIP_MOCK_TESTS` affects which tests run so it must be added as input for proper cache invalidation. + inputs.property("skipMockTests", System.getenv("SKIP_MOCK_TESTS")).optional(true) } val ktfmt by configurations.creating From 4d5ceddde1679e02e3ac1c089e068cc7e55d8900 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 Jan 2026 05:24:12 +0000 Subject: [PATCH 092/164] fix(client): preserve time zone in lenient date-time parsing --- .../com/browserbase/api/core/ObjectMappers.kt | 19 +++++---- .../browserbase/api/core/ObjectMappersTest.kt | 41 +++++++++++++++---- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt index 06367fe..5200d47 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt @@ -25,7 +25,7 @@ import java.time.DateTimeException import java.time.LocalDate import java.time.LocalDateTime import java.time.OffsetDateTime -import java.time.ZonedDateTime +import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField @@ -157,14 +157,15 @@ private class LenientOffsetDateTimeDeserializer : val temporal = formatter.parse(p.text) return when { - !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> - LocalDate.from(temporal).atStartOfDay() - !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> - LocalDateTime.from(temporal) - else -> ZonedDateTime.from(temporal).toLocalDateTime() - } - .atZone(context.timeZone.toZoneId()) - .toOffsetDateTime() + !temporal.isSupported(ChronoField.HOUR_OF_DAY) -> + LocalDate.from(temporal) + .atStartOfDay() + .atZone(ZoneId.of("UTC")) + .toOffsetDateTime() + !temporal.isSupported(ChronoField.OFFSET_SECONDS) -> + LocalDateTime.from(temporal).atZone(ZoneId.of("UTC")).toOffsetDateTime() + else -> OffsetDateTime.from(temporal) + } } catch (e: DateTimeException) { exceptions.add(e) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt index bc80611..62c4108 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ObjectMappersTest.kt @@ -3,12 +3,14 @@ package com.browserbase.api.core import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.exc.MismatchedInputException import com.fasterxml.jackson.module.kotlin.readValue +import java.time.LocalDate +import java.time.LocalTime import java.time.OffsetDateTime +import java.time.ZoneOffset import kotlin.reflect.KClass import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.catchThrowable import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource import org.junitpioneer.jupiter.cartesian.CartesianTest @@ -72,11 +74,34 @@ internal class ObjectMappersTest { } } - enum class LenientOffsetDateTimeTestCase(val string: String) { - DATE("1998-04-21"), - DATE_TIME("1998-04-21T04:00:00"), - ZONED_DATE_TIME_1("1998-04-21T04:00:00+03:00"), - ZONED_DATE_TIME_2("1998-04-21T04:00:00Z"), + enum class LenientOffsetDateTimeTestCase( + val string: String, + val expectedOffsetDateTime: OffsetDateTime, + ) { + DATE( + "1998-04-21", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(0, 0), ZoneOffset.UTC), + ), + DATE_TIME( + "1998-04-21T04:00:00", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(4, 0), ZoneOffset.UTC), + ), + ZONED_DATE_TIME_1( + "1998-04-21T04:00:00+03:00", + expectedOffsetDateTime = + OffsetDateTime.of( + LocalDate.of(1998, 4, 21), + LocalTime.of(4, 0), + ZoneOffset.ofHours(3), + ), + ), + ZONED_DATE_TIME_2( + "1998-04-21T04:00:00Z", + expectedOffsetDateTime = + OffsetDateTime.of(LocalDate.of(1998, 4, 21), LocalTime.of(4, 0), ZoneOffset.UTC), + ), } @ParameterizedTest @@ -85,6 +110,8 @@ internal class ObjectMappersTest { val jsonMapper = jsonMapper() val json = jsonMapper.writeValueAsString(testCase.string) - assertDoesNotThrow { jsonMapper().readValue(json) } + val offsetDateTime = jsonMapper().readValue(json) + + assertThat(offsetDateTime).isEqualTo(testCase.expectedOffsetDateTime) } } From 02861606b41fbc328986c8f5f7e48dc65815fc73 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 24 Jan 2026 05:05:31 +0000 Subject: [PATCH 093/164] chore(ci): upgrade `actions/github-script` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49979dd..27fda9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: - name: Get GitHub OIDC Token if: github.repository == 'stainless-sdks/stagehand-java' id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); From ee9b93162893bf275691c6536641a771095a016d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 01:50:16 +0000 Subject: [PATCH 094/164] feat(api): manual updates --- .stats.yml | 2 +- LICENSE | 202 +----------------- .../main/kotlin/stagehand.publish.gradle.kts | 2 +- 3 files changed, 6 insertions(+), 200 deletions(-) diff --git a/.stats.yml b/.stats.yml index 094239e..b1b40bd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-089c8670f1d7c2e9fa8e5c97010db7c24b8f162eb7cfe76ffa41d70fa46efe2f.yml openapi_spec_hash: 7a226aee8f3f2ab16febbe6bb35e1657 -config_hash: 8e4ed6629c178aa0c8aaf575cb07c544 +config_hash: 242651c4871c2869ba3c2e3d337505b9 diff --git a/LICENSE b/LICENSE index d15d021..a7b82c2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,7 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +Copyright 2026 stagehand - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - 1. Definitions. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2026 Stagehand - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index facd8ed..f424b58 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -15,7 +15,7 @@ configure { licenses { license { - name.set("Apache-2.0") + name.set("MIT") } } From 4eaa81e225244a91adf84a45f9d0c67896a44a55 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:38:27 +0000 Subject: [PATCH 095/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index b1b40bd..d8e68da 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-089c8670f1d7c2e9fa8e5c97010db7c24b8f162eb7cfe76ffa41d70fa46efe2f.yml openapi_spec_hash: 7a226aee8f3f2ab16febbe6bb35e1657 -config_hash: 242651c4871c2869ba3c2e3d337505b9 +config_hash: 75b561cd2ba925e4f2a62ec2f1d13738 From 5fcf483a820a80d5bf95738120fcd3d5479b1d4f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:41:13 +0000 Subject: [PATCH 096/164] feat: add auto-bedrock support based on bedrock/provider.model-name --- .stats.yml | 4 +- .../models/sessions/SessionExecuteParams.kt | 187 +++++++++++++++++- .../sessions/SessionExecuteParamsTest.kt | 4 + .../services/async/SessionServiceAsyncTest.kt | 2 + .../services/blocking/SessionServiceTest.kt | 2 + 5 files changed, 191 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index d8e68da..f3c17f9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-089c8670f1d7c2e9fa8e5c97010db7c24b8f162eb7cfe76ffa41d70fa46efe2f.yml -openapi_spec_hash: 7a226aee8f3f2ab16febbe6bb35e1657 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-43e6dd4ce19381de488d296e9036fea15bfea9a6f946cf8ccf4e02aecc8fb765.yml +openapi_spec_hash: f736e7a8acea0d73e1031c86ea803246 config_hash: 75b561cd2ba925e4f2a62ec2f1d13738 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index b5658a5..31c9121 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -676,6 +676,7 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val cua: JsonField, + private val mode: JsonField, private val model: JsonField, private val provider: JsonField, private val systemPrompt: JsonField, @@ -685,6 +686,7 @@ private constructor( @JsonCreator private constructor( @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), + @JsonProperty("mode") @ExcludeMissing mode: JsonField = JsonMissing.of(), @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("provider") @ExcludeMissing @@ -692,16 +694,24 @@ private constructor( @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - ) : this(cua, model, provider, systemPrompt, mutableMapOf()) + ) : this(cua, mode, model, provider, systemPrompt, mutableMapOf()) /** - * Enable Computer Use Agent mode + * Deprecated. Use mode: 'cua' instead. If both are provided, mode takes precedence. * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ fun cua(): Optional = cua.getOptional("cua") + /** + * Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun mode(): Optional = mode.getOptional("mode") + /** * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') * @@ -733,6 +743,13 @@ private constructor( */ @JsonProperty("cua") @ExcludeMissing fun _cua(): JsonField = cua + /** + * Returns the raw JSON value of [mode]. + * + * Unlike [mode], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("mode") @ExcludeMissing fun _mode(): JsonField = mode + /** * Returns the raw JSON value of [model]. * @@ -779,6 +796,7 @@ private constructor( class Builder internal constructor() { private var cua: JsonField = JsonMissing.of() + private var mode: JsonField = JsonMissing.of() private var model: JsonField = JsonMissing.of() private var provider: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() @@ -787,13 +805,14 @@ private constructor( @JvmSynthetic internal fun from(agentConfig: AgentConfig) = apply { cua = agentConfig.cua + mode = agentConfig.mode model = agentConfig.model provider = agentConfig.provider systemPrompt = agentConfig.systemPrompt additionalProperties = agentConfig.additionalProperties.toMutableMap() } - /** Enable Computer Use Agent mode */ + /** Deprecated. Use mode: 'cua' instead. If both are provided, mode takes precedence. */ fun cua(cua: Boolean) = cua(JsonField.of(cua)) /** @@ -805,6 +824,18 @@ private constructor( */ fun cua(cua: JsonField) = apply { this.cua = cua } + /** Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. */ + fun mode(mode: Mode) = mode(JsonField.of(mode)) + + /** + * Sets [Builder.mode] to an arbitrary JSON value. + * + * You should usually call [Builder.mode] with a well-typed [Mode] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun mode(mode: JsonField) = apply { this.mode = mode } + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ fun model(model: Model) = model(JsonField.of(model)) @@ -874,7 +905,14 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): AgentConfig = - AgentConfig(cua, model, provider, systemPrompt, additionalProperties.toMutableMap()) + AgentConfig( + cua, + mode, + model, + provider, + systemPrompt, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -885,6 +923,7 @@ private constructor( } cua() + mode().ifPresent { it.validate() } model().ifPresent { it.validate() } provider().ifPresent { it.validate() } systemPrompt() @@ -908,10 +947,145 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (cua.asKnown().isPresent) 1 else 0) + + (mode.asKnown().getOrNull()?.validity() ?: 0) + (model.asKnown().getOrNull()?.validity() ?: 0) + (provider.asKnown().getOrNull()?.validity() ?: 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + /** Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. */ + class Mode @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val DOM = of("dom") + + @JvmField val HYBRID = of("hybrid") + + @JvmField val CUA = of("cua") + + @JvmStatic fun of(value: String) = Mode(JsonField.of(value)) + } + + /** An enum containing [Mode]'s known values. */ + enum class Known { + DOM, + HYBRID, + CUA, + } + + /** + * An enum containing [Mode]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Mode] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + DOM, + HYBRID, + CUA, + /** An enum member indicating that [Mode] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + DOM -> Value.DOM + HYBRID -> Value.HYBRID + CUA -> Value.CUA + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + DOM -> Known.DOM + HYBRID -> Known.HYBRID + CUA -> Known.CUA + else -> throw StagehandInvalidDataException("Unknown Mode: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Mode = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Mode && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ @JsonDeserialize(using = Model.Deserializer::class) @JsonSerialize(using = Model.Serializer::class) @@ -1234,6 +1408,7 @@ private constructor( return other is AgentConfig && cua == other.cua && + mode == other.mode && model == other.model && provider == other.provider && systemPrompt == other.systemPrompt && @@ -1241,13 +1416,13 @@ private constructor( } private val hashCode: Int by lazy { - Objects.hash(cua, model, provider, systemPrompt, additionalProperties) + Objects.hash(cua, mode, model, provider, systemPrompt, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "AgentConfig{cua=$cua, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" + "AgentConfig{cua=$cua, mode=$mode, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" } class ExecuteOptions diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index cfa5176..6d5e08e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -16,6 +16,7 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") @@ -71,6 +72,7 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") @@ -130,6 +132,7 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") @@ -161,6 +164,7 @@ internal class SessionExecuteParamsTest { .isEqualTo( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 42eb483..498cad7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -154,6 +154,7 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") @@ -204,6 +205,7 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 8b05e95..58bee25 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -152,6 +152,7 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") @@ -201,6 +202,7 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() .modelName("openai/gpt-5-nano") From f4ea5146dc0d1ee58ccc7cf4832a8b7f13b0095f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 05:32:23 +0000 Subject: [PATCH 097/164] fix(docs): fix mcp installation instructions for remote servers --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d564ca..58d1f5c 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ It is generated with [Stainless](https://www.stainless.com/). Use the Stagehand MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=stagehand-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN0YWdlaGFuZC1tY3AiXX0) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22stagehand-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22stagehand-mcp%22%5D%7D) +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=stagehand-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN0YWdlaGFuZC1tY3AiXSwiZW52Ijp7IkJST1dTRVJCQVNFX0FQSV9LRVkiOiJNeSBCcm93c2VyYmFzZSBBUEkgS2V5IiwiQlJPV1NFUkJBU0VfUFJPSkVDVF9JRCI6Ik15IEJyb3dzZXJiYXNlIFByb2plY3QgSUQiLCJNT0RFTF9BUElfS0VZIjoiTXkgTW9kZWwgQVBJIEtleSJ9fQ) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22stagehand-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22stagehand-mcp%22%5D%2C%22env%22%3A%7B%22BROWSERBASE_API_KEY%22%3A%22My%20Browserbase%20API%20Key%22%2C%22BROWSERBASE_PROJECT_ID%22%3A%22My%20Browserbase%20Project%20ID%22%2C%22MODEL_API_KEY%22%3A%22My%20Model%20API%20Key%22%7D%7D) > Note: You may need to set environment variables in your MCP client. From bb9a02d6d63444ede8141f1cef29a1636e734ff6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 19:13:37 +0000 Subject: [PATCH 098/164] feat: Update stainless.yml for project and publish settings --- .github/workflows/publish-sonatype.yml | 2 +- .stats.yml | 2 +- README.md | 2 + build.gradle.kts | 13 --- buildSrc/build.gradle.kts | 3 + .../src/main/kotlin/stagehand.java.gradle.kts | 9 -- .../main/kotlin/stagehand.publish.gradle.kts | 105 +++++++++--------- .../api/core/handlers/SseHandler.kt | 2 +- 8 files changed, 62 insertions(+), 76 deletions(-) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index d01e5dd..e0e380c 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -33,7 +33,7 @@ jobs: 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 publish --no-configuration-cache + ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache env: SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index f3c17f9..da47671 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-43e6dd4ce19381de488d296e9036fea15bfea9a6f946cf8ccf4e02aecc8fb765.yml openapi_spec_hash: f736e7a8acea0d73e1031c86ea803246 -config_hash: 75b561cd2ba925e4f2a62ec2f1d13738 +config_hash: b375728ccf7d33287335852f4f59c293 diff --git a/README.md b/README.md index 58d1f5c..4be09bd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://docs.stagehand.dev) from applications written in Java. +The Stagehand Java SDK is similar to the Stagehand Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. + It is generated with [Stainless](https://www.stainless.com/). ## MCP Server diff --git a/build.gradle.kts b/build.gradle.kts index 7c2c0c2..49dfc3e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,4 @@ plugins { - id("io.github.gradle-nexus.publish-plugin") version "1.1.0" id("org.jetbrains.dokka") version "2.0.0" } @@ -35,15 +34,3 @@ tasks.named("dokkaJavadocCollector").configure { .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } - -nexusPublishing { - repositories { - sonatype { - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) - - username.set(System.getenv("SONATYPE_USERNAME")) - password.set(System.getenv("SONATYPE_PASSWORD")) - } - } -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0b14135..c6dc92e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,12 +1,15 @@ plugins { `kotlin-dsl` kotlin("jvm") version "1.9.20" + id("com.vanniktech.maven.publish") version "0.28.0" } repositories { gradlePluginPortal() + mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") + implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0") } diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts index 81d5d32..70fc33f 100644 --- a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -8,11 +8,6 @@ repositories { mavenCentral() } -configure { - withJavadocJar() - withSourcesJar() -} - java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) @@ -27,10 +22,6 @@ tasks.withType().configureEach { options.release.set(8) } -tasks.named("javadocJar") { - setZip64(true) -} - tasks.named("jar") { manifest { attributes(mapOf( diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index f424b58..f45a9d7 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -1,68 +1,71 @@ +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinJvm +import com.vanniktech.maven.publish.MavenPublishBaseExtension +import com.vanniktech.maven.publish.SonatypeHost + plugins { - `maven-publish` - signing + id("com.vanniktech.maven.publish") +} + +publishing { + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } } -configure { - publications { - register("maven") { - from(components["java"]) +repositories { + gradlePluginPortal() + mavenCentral() +} - pom { - name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") - url.set("https://docs.stagehand.dev") +extra["signingInMemoryKey"] = System.getenv("GPG_SIGNING_KEY") +extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") +extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") - licenses { - license { - name.set("MIT") - } - } +configure { + if (!project.hasProperty("publishLocal")) { + signAllPublications() + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + } - developers { - developer { - name.set("Stagehand") - } - } + coordinates(project.group.toString(), project.name, project.version.toString()) + configure( + KotlinJvm( + javadocJar = JavadocJar.Dokka("dokkaJavadoc"), + sourcesJar = true, + ) + ) - scm { - connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - url.set("https://github.com/browserbase/stagehand-java") - } + pom { + name.set("Stagehand API") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + url.set("https://docs.stagehand.dev") - versionMapping { - allVariants { - fromResolutionResult() - } - } + licenses { + license { + name.set("MIT") } } - } - repositories { - if (project.hasProperty("publishLocal")) { - maven { - name = "LocalFileSystem" - url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + + developers { + developer { + name.set("Stagehand") } } - } -} -signing { - val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null } - val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null } - val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null } - if (signingKey != null && signingPassword != null) { - useInMemoryPgpKeys( - signingKeyId, - signingKey, - signingPassword, - ) - sign(publishing.publications["maven"]) + scm { + connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + url.set("https://github.com/browserbase/stagehand-java") + } } } -tasks.named("publish") { - dependsOn(":closeAndReleaseSonatypeStagingRepository") +tasks.withType().configureEach { + isZip64 = true } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt index 039faae..f8e870e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -28,7 +28,7 @@ internal fun sseHandler(jsonMapper: JsonMapper): Handler { + message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> { // In this case we don't break because we still want to iterate through the full // stream. done = true From 6e9c2c0851f5bceb9e453e3a9f96a7e330936b29 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 Jan 2026 21:22:53 +0000 Subject: [PATCH 099/164] feat: Add executionModel serialization to api client --- .github/workflows/publish-sonatype.yml | 2 +- .stats.yml | 6 +- README.md | 2 - build.gradle.kts | 13 + buildSrc/build.gradle.kts | 3 - .../src/main/kotlin/stagehand.java.gradle.kts | 9 + .../main/kotlin/stagehand.publish.gradle.kts | 105 ++++---- .../api/core/handlers/SseHandler.kt | 2 +- .../models/sessions/SessionExecuteParams.kt | 255 +++++++++++++++++- .../sessions/SessionExecuteParamsTest.kt | 32 +++ .../services/async/SessionServiceAsyncTest.kt | 16 ++ .../services/blocking/SessionServiceTest.kt | 16 ++ 12 files changed, 394 insertions(+), 67 deletions(-) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index e0e380c..d01e5dd 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -33,7 +33,7 @@ jobs: 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 + ./gradlew publish --no-configuration-cache env: SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index da47671..e42f0bb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-43e6dd4ce19381de488d296e9036fea15bfea9a6f946cf8ccf4e02aecc8fb765.yml -openapi_spec_hash: f736e7a8acea0d73e1031c86ea803246 -config_hash: b375728ccf7d33287335852f4f59c293 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8fbb3fa8f3a37c1c7408de427fe125aadec49f705e8e30d191601a9b69c4cc41.yml +openapi_spec_hash: 48b4dfac35a842d7fb0d228caf87544e +config_hash: 242651c4871c2869ba3c2e3d337505b9 diff --git a/README.md b/README.md index 4be09bd..58d1f5c 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@ The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://docs.stagehand.dev) from applications written in Java. -The Stagehand Java SDK is similar to the Stagehand Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. - It is generated with [Stainless](https://www.stainless.com/). ## MCP Server diff --git a/build.gradle.kts b/build.gradle.kts index 49dfc3e..7c2c0c2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,5 @@ plugins { + id("io.github.gradle-nexus.publish-plugin") version "1.1.0" id("org.jetbrains.dokka") version "2.0.0" } @@ -34,3 +35,15 @@ tasks.named("dokkaJavadocCollector").configure { .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } + +nexusPublishing { + repositories { + sonatype { + nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) + snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) + + username.set(System.getenv("SONATYPE_USERNAME")) + password.set(System.getenv("SONATYPE_PASSWORD")) + } + } +} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index c6dc92e..0b14135 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,15 +1,12 @@ plugins { `kotlin-dsl` kotlin("jvm") version "1.9.20" - id("com.vanniktech.maven.publish") version "0.28.0" } repositories { gradlePluginPortal() - mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") - implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0") } diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts index 70fc33f..81d5d32 100644 --- a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -8,6 +8,11 @@ repositories { mavenCentral() } +configure { + withJavadocJar() + withSourcesJar() +} + java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) @@ -22,6 +27,10 @@ tasks.withType().configureEach { options.release.set(8) } +tasks.named("javadocJar") { + setZip64(true) +} + tasks.named("jar") { manifest { attributes(mapOf( diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index f45a9d7..f424b58 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -1,71 +1,68 @@ -import com.vanniktech.maven.publish.JavadocJar -import com.vanniktech.maven.publish.KotlinJvm -import com.vanniktech.maven.publish.MavenPublishBaseExtension -import com.vanniktech.maven.publish.SonatypeHost - plugins { - id("com.vanniktech.maven.publish") -} - -publishing { - repositories { - if (project.hasProperty("publishLocal")) { - maven { - name = "LocalFileSystem" - url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") - } - } - } + `maven-publish` + signing } -repositories { - gradlePluginPortal() - mavenCentral() -} +configure { + publications { + register("maven") { + from(components["java"]) -extra["signingInMemoryKey"] = System.getenv("GPG_SIGNING_KEY") -extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") -extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") + pom { + name.set("Stagehand API") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + url.set("https://docs.stagehand.dev") -configure { - if (!project.hasProperty("publishLocal")) { - signAllPublications() - publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) - } + licenses { + license { + name.set("MIT") + } + } - coordinates(project.group.toString(), project.name, project.version.toString()) - configure( - KotlinJvm( - javadocJar = JavadocJar.Dokka("dokkaJavadoc"), - sourcesJar = true, - ) - ) + developers { + developer { + name.set("Stagehand") + } + } - pom { - name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") - url.set("https://docs.stagehand.dev") + scm { + connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + url.set("https://github.com/browserbase/stagehand-java") + } - licenses { - license { - name.set("MIT") + versionMapping { + allVariants { + fromResolutionResult() + } + } } } - - developers { - developer { - name.set("Stagehand") + } + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") } } + } +} - scm { - connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - url.set("https://github.com/browserbase/stagehand-java") - } +signing { + val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null } + val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null } + val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null } + if (signingKey != null && signingPassword != null) { + useInMemoryPgpKeys( + signingKeyId, + signingKey, + signingPassword, + ) + sign(publishing.publications["maven"]) } } -tasks.withType().configureEach { - isZip64 = true +tasks.named("publish") { + dependsOn(":closeAndReleaseSonatypeStagingRepository") } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt index f8e870e..039faae 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -28,7 +28,7 @@ internal fun sseHandler(jsonMapper: JsonMapper): Handler { + message.data.startsWith("finished") -> { // In this case we don't break because we still want to iterate through the full // stream. done = true diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 31c9121..b8a795f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -676,6 +676,7 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val cua: JsonField, + private val executionModel: JsonField, private val mode: JsonField, private val model: JsonField, private val provider: JsonField, @@ -686,6 +687,9 @@ private constructor( @JsonCreator private constructor( @JsonProperty("cua") @ExcludeMissing cua: JsonField = JsonMissing.of(), + @JsonProperty("executionModel") + @ExcludeMissing + executionModel: JsonField = JsonMissing.of(), @JsonProperty("mode") @ExcludeMissing mode: JsonField = JsonMissing.of(), @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("provider") @@ -694,7 +698,7 @@ private constructor( @JsonProperty("systemPrompt") @ExcludeMissing systemPrompt: JsonField = JsonMissing.of(), - ) : this(cua, mode, model, provider, systemPrompt, mutableMapOf()) + ) : this(cua, executionModel, mode, model, provider, systemPrompt, mutableMapOf()) /** * Deprecated. Use mode: 'cua' instead. If both are provided, mode takes precedence. @@ -704,6 +708,17 @@ private constructor( */ fun cua(): Optional = cua.getOptional("cua") + /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') for tool + * execution (observe/act calls within agent tools). If not specified, inherits from the + * main model configuration. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun executionModel(): Optional = + executionModel.getOptional("executionModel") + /** * Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. * @@ -743,6 +758,16 @@ private constructor( */ @JsonProperty("cua") @ExcludeMissing fun _cua(): JsonField = cua + /** + * Returns the raw JSON value of [executionModel]. + * + * Unlike [executionModel], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("executionModel") + @ExcludeMissing + fun _executionModel(): JsonField = executionModel + /** * Returns the raw JSON value of [mode]. * @@ -796,6 +821,7 @@ private constructor( class Builder internal constructor() { private var cua: JsonField = JsonMissing.of() + private var executionModel: JsonField = JsonMissing.of() private var mode: JsonField = JsonMissing.of() private var model: JsonField = JsonMissing.of() private var provider: JsonField = JsonMissing.of() @@ -805,6 +831,7 @@ private constructor( @JvmSynthetic internal fun from(agentConfig: AgentConfig) = apply { cua = agentConfig.cua + executionModel = agentConfig.executionModel mode = agentConfig.mode model = agentConfig.model provider = agentConfig.provider @@ -824,6 +851,34 @@ private constructor( */ fun cua(cua: JsonField) = apply { this.cua = cua } + /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') for tool + * execution (observe/act calls within agent tools). If not specified, inherits from the + * main model configuration. + */ + fun executionModel(executionModel: ExecutionModel) = + executionModel(JsonField.of(executionModel)) + + /** + * Sets [Builder.executionModel] to an arbitrary JSON value. + * + * You should usually call [Builder.executionModel] with a well-typed [ExecutionModel] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun executionModel(executionModel: JsonField) = apply { + this.executionModel = executionModel + } + + /** + * Alias for calling [executionModel] with `ExecutionModel.ofModelConfig(modelConfig)`. + */ + fun executionModel(modelConfig: ModelConfig) = + executionModel(ExecutionModel.ofModelConfig(modelConfig)) + + /** Alias for calling [executionModel] with `ExecutionModel.ofString(string)`. */ + fun executionModel(string: String) = executionModel(ExecutionModel.ofString(string)) + /** Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. */ fun mode(mode: Mode) = mode(JsonField.of(mode)) @@ -907,6 +962,7 @@ private constructor( fun build(): AgentConfig = AgentConfig( cua, + executionModel, mode, model, provider, @@ -923,6 +979,7 @@ private constructor( } cua() + executionModel().ifPresent { it.validate() } mode().ifPresent { it.validate() } model().ifPresent { it.validate() } provider().ifPresent { it.validate() } @@ -947,11 +1004,194 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (cua.asKnown().isPresent) 1 else 0) + + (executionModel.asKnown().getOrNull()?.validity() ?: 0) + (mode.asKnown().getOrNull()?.validity() ?: 0) + (model.asKnown().getOrNull()?.validity() ?: 0) + (provider.asKnown().getOrNull()?.validity() ?: 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + /** + * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') for tool + * execution (observe/act calls within agent tools). If not specified, inherits from the + * main model configuration. + */ + @JsonDeserialize(using = ExecutionModel.Deserializer::class) + @JsonSerialize(using = ExecutionModel.Serializer::class) + class ExecutionModel + private constructor( + private val modelConfig: ModelConfig? = null, + private val string: String? = null, + private val _json: JsonValue? = null, + ) { + + fun modelConfig(): Optional = Optional.ofNullable(modelConfig) + + fun string(): Optional = Optional.ofNullable(string) + + fun isModelConfig(): Boolean = modelConfig != null + + fun isString(): Boolean = string != null + + fun asModelConfig(): ModelConfig = modelConfig.getOrThrow("modelConfig") + + fun asString(): String = string.getOrThrow("string") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + modelConfig != null -> visitor.visitModelConfig(modelConfig) + string != null -> visitor.visitString(string) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ExecutionModel = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitModelConfig(modelConfig: ModelConfig) { + modelConfig.validate() + } + + override fun visitString(string: String) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitModelConfig(modelConfig: ModelConfig) = + modelConfig.validity() + + override fun visitString(string: String) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ExecutionModel && + modelConfig == other.modelConfig && + string == other.string + } + + override fun hashCode(): Int = Objects.hash(modelConfig, string) + + override fun toString(): String = + when { + modelConfig != null -> "ExecutionModel{modelConfig=$modelConfig}" + string != null -> "ExecutionModel{string=$string}" + _json != null -> "ExecutionModel{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ExecutionModel") + } + + companion object { + + @JvmStatic + fun ofModelConfig(modelConfig: ModelConfig) = + ExecutionModel(modelConfig = modelConfig) + + @JvmStatic fun ofString(string: String) = ExecutionModel(string = string) + } + + /** + * An interface that defines how to map each variant of [ExecutionModel] to a value of + * type [T]. + */ + interface Visitor { + + fun visitModelConfig(modelConfig: ModelConfig): T + + fun visitString(string: String): T + + /** + * Maps an unknown variant of [ExecutionModel] to a value of type [T]. + * + * An instance of [ExecutionModel] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the + * SDK is on an older version than the API, then the API may respond with new + * variants that the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown ExecutionModel: $json") + } + } + + internal class Deserializer : BaseDeserializer(ExecutionModel::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ExecutionModel { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + ExecutionModel(modelConfig = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ExecutionModel(string = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from boolean). + 0 -> ExecutionModel(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(ExecutionModel::class) { + + override fun serialize( + value: ExecutionModel, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.modelConfig != null -> generator.writeObject(value.modelConfig) + value.string != null -> generator.writeObject(value.string) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ExecutionModel") + } + } + } + } + /** Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. */ class Mode @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1408,6 +1648,7 @@ private constructor( return other is AgentConfig && cua == other.cua && + executionModel == other.executionModel && mode == other.mode && model == other.model && provider == other.provider && @@ -1416,13 +1657,21 @@ private constructor( } private val hashCode: Int by lazy { - Objects.hash(cua, mode, model, provider, systemPrompt, additionalProperties) + Objects.hash( + cua, + executionModel, + mode, + model, + provider, + systemPrompt, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "AgentConfig{cua=$cua, mode=$mode, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" + "AgentConfig{cua=$cua, executionModel=$executionModel, mode=$mode, model=$model, provider=$provider, systemPrompt=$systemPrompt, additionalProperties=$additionalProperties}" } class ExecuteOptions diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index 6d5e08e..cb26cb2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -16,6 +16,14 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() @@ -72,6 +80,14 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() @@ -132,6 +148,14 @@ internal class SessionExecuteParamsTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() @@ -164,6 +188,14 @@ internal class SessionExecuteParamsTest { .isEqualTo( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 498cad7..889335e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -154,6 +154,14 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() @@ -205,6 +213,14 @@ internal class SessionServiceAsyncTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 58bee25..d9c3ea3 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -152,6 +152,14 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() @@ -202,6 +210,14 @@ internal class SessionServiceTest { .agentConfig( SessionExecuteParams.AgentConfig.builder() .cua(true) + .executionModel( + ModelConfig.builder() + .modelName("openai/gpt-5-nano") + .apiKey("sk-some-openai-api-key") + .baseUrl("https://api.openai.com/v1") + .provider(ModelConfig.Provider.OPENAI) + .build() + ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() From 248f50edab3866471d95e15be37066881e195ed0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 31 Jan 2026 00:28:05 +0000 Subject: [PATCH 100/164] feat: Removed MCP from readme for now --- .github/workflows/publish-sonatype.yml | 2 +- .stats.yml | 2 +- README.md | 11 +- build.gradle.kts | 13 --- buildSrc/build.gradle.kts | 3 + .../src/main/kotlin/stagehand.java.gradle.kts | 9 -- .../main/kotlin/stagehand.publish.gradle.kts | 105 +++++++++--------- .../api/core/handlers/SseHandler.kt | 2 +- 8 files changed, 62 insertions(+), 85 deletions(-) diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index d01e5dd..e0e380c 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -33,7 +33,7 @@ jobs: 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 publish --no-configuration-cache + ./gradlew publishAndReleaseToMavenCentral --stacktrace -PmavenCentralUsername="$SONATYPE_USERNAME" -PmavenCentralPassword="$SONATYPE_PASSWORD" --no-configuration-cache env: SONATYPE_USERNAME: ${{ secrets.STAGEHAND_SONATYPE_USERNAME || secrets.SONATYPE_USERNAME }} SONATYPE_PASSWORD: ${{ secrets.STAGEHAND_SONATYPE_PASSWORD || secrets.SONATYPE_PASSWORD }} diff --git a/.stats.yml b/.stats.yml index e42f0bb..9738f87 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8fbb3fa8f3a37c1c7408de427fe125aadec49f705e8e30d191601a9b69c4cc41.yml openapi_spec_hash: 48b4dfac35a842d7fb0d228caf87544e -config_hash: 242651c4871c2869ba3c2e3d337505b9 +config_hash: 7386d24e2f03a3b2a89b3f6881446348 diff --git a/README.md b/README.md index 58d1f5c..4d35164 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,9 @@ The Stagehand Java SDK provides convenient access to the [Stagehand REST API](https://docs.stagehand.dev) from applications written in Java. -It is generated with [Stainless](https://www.stainless.com/). - -## MCP Server - -Use the Stagehand MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. +The Stagehand Java SDK is similar to the Stagehand Kotlin SDK but with minor differences that make it more ergonomic for use in Java, such as `Optional` instead of nullable values, `Stream` instead of `Sequence`, and `CompletableFuture` instead of suspend functions. -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=stagehand-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN0YWdlaGFuZC1tY3AiXSwiZW52Ijp7IkJST1dTRVJCQVNFX0FQSV9LRVkiOiJNeSBCcm93c2VyYmFzZSBBUEkgS2V5IiwiQlJPV1NFUkJBU0VfUFJPSkVDVF9JRCI6Ik15IEJyb3dzZXJiYXNlIFByb2plY3QgSUQiLCJNT0RFTF9BUElfS0VZIjoiTXkgTW9kZWwgQVBJIEtleSJ9fQ) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22stagehand-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22stagehand-mcp%22%5D%2C%22env%22%3A%7B%22BROWSERBASE_API_KEY%22%3A%22My%20Browserbase%20API%20Key%22%2C%22BROWSERBASE_PROJECT_ID%22%3A%22My%20Browserbase%20Project%20ID%22%2C%22MODEL_API_KEY%22%3A%22My%20Model%20API%20Key%22%7D%7D) - -> Note: You may need to set environment variables in your MCP client. +It is generated with [Stainless](https://www.stainless.com/). diff --git a/build.gradle.kts b/build.gradle.kts index 7c2c0c2..49dfc3e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,4 @@ plugins { - id("io.github.gradle-nexus.publish-plugin") version "1.1.0" id("org.jetbrains.dokka") version "2.0.0" } @@ -35,15 +34,3 @@ tasks.named("dokkaJavadocCollector").configure { .filter { it.project.name != "stagehand-java" && it.name == "dokkaJavadocJar" } .forEach { mustRunAfter(it) } } - -nexusPublishing { - repositories { - sonatype { - nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) - snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")) - - username.set(System.getenv("SONATYPE_USERNAME")) - password.set(System.getenv("SONATYPE_PASSWORD")) - } - } -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0b14135..c6dc92e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,12 +1,15 @@ plugins { `kotlin-dsl` kotlin("jvm") version "1.9.20" + id("com.vanniktech.maven.publish") version "0.28.0" } repositories { gradlePluginPortal() + mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20") + implementation("com.vanniktech:gradle-maven-publish-plugin:0.28.0") } diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts index 81d5d32..70fc33f 100644 --- a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -8,11 +8,6 @@ repositories { mavenCentral() } -configure { - withJavadocJar() - withSourcesJar() -} - java { toolchain { languageVersion.set(JavaLanguageVersion.of(21)) @@ -27,10 +22,6 @@ tasks.withType().configureEach { options.release.set(8) } -tasks.named("javadocJar") { - setZip64(true) -} - tasks.named("jar") { manifest { attributes(mapOf( diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index f424b58..f45a9d7 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -1,68 +1,71 @@ +import com.vanniktech.maven.publish.JavadocJar +import com.vanniktech.maven.publish.KotlinJvm +import com.vanniktech.maven.publish.MavenPublishBaseExtension +import com.vanniktech.maven.publish.SonatypeHost + plugins { - `maven-publish` - signing + id("com.vanniktech.maven.publish") +} + +publishing { + repositories { + if (project.hasProperty("publishLocal")) { + maven { + name = "LocalFileSystem" + url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + } + } + } } -configure { - publications { - register("maven") { - from(components["java"]) +repositories { + gradlePluginPortal() + mavenCentral() +} - pom { - name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") - url.set("https://docs.stagehand.dev") +extra["signingInMemoryKey"] = System.getenv("GPG_SIGNING_KEY") +extra["signingInMemoryKeyId"] = System.getenv("GPG_SIGNING_KEY_ID") +extra["signingInMemoryKeyPassword"] = System.getenv("GPG_SIGNING_PASSWORD") - licenses { - license { - name.set("MIT") - } - } +configure { + if (!project.hasProperty("publishLocal")) { + signAllPublications() + publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) + } - developers { - developer { - name.set("Stagehand") - } - } + coordinates(project.group.toString(), project.name, project.version.toString()) + configure( + KotlinJvm( + javadocJar = JavadocJar.Dokka("dokkaJavadoc"), + sourcesJar = true, + ) + ) - scm { - connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") - url.set("https://github.com/browserbase/stagehand-java") - } + pom { + name.set("Stagehand API") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + url.set("https://docs.stagehand.dev") - versionMapping { - allVariants { - fromResolutionResult() - } - } + licenses { + license { + name.set("MIT") } } - } - repositories { - if (project.hasProperty("publishLocal")) { - maven { - name = "LocalFileSystem" - url = uri("${rootProject.layout.buildDirectory.get()}/local-maven-repo") + + developers { + developer { + name.set("Stagehand") } } - } -} -signing { - val signingKeyId = System.getenv("GPG_SIGNING_KEY_ID")?.ifBlank { null } - val signingKey = System.getenv("GPG_SIGNING_KEY")?.ifBlank { null } - val signingPassword = System.getenv("GPG_SIGNING_PASSWORD")?.ifBlank { null } - if (signingKey != null && signingPassword != null) { - useInMemoryPgpKeys( - signingKeyId, - signingKey, - signingPassword, - ) - sign(publishing.publications["maven"]) + scm { + connection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + developerConnection.set("scm:git:git://github.com/browserbase/stagehand-java.git") + url.set("https://github.com/browserbase/stagehand-java") + } } } -tasks.named("publish") { - dependsOn(":closeAndReleaseSonatypeStagingRepository") +tasks.withType().configureEach { + isZip64 = true } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt index 039faae..f8e870e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -28,7 +28,7 @@ internal fun sseHandler(jsonMapper: JsonMapper): Handler { + message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> { // In this case we don't break because we still want to iterate through the full // stream. done = true From 6c2353e29346245842c2aa9ac61cf1691005c25d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 31 Jan 2026 06:10:05 +0000 Subject: [PATCH 101/164] chore(internal): allow passing args to `./scripts/test` --- scripts/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build b/scripts/build index f406348..16a2b00 100755 --- a/scripts/build +++ b/scripts/build @@ -5,4 +5,4 @@ set -e cd "$(dirname "$0")/.." echo "==> Building classes" -./gradlew build testClasses -x test +./gradlew build testClasses "$@" -x test From 28eb488a4cd341cddaa579292b0ebd255df32f42 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Feb 2026 23:52:13 +0000 Subject: [PATCH 102/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 9738f87..a0da57a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8fbb3fa8f3a37c1c7408de427fe125aadec49f705e8e30d191601a9b69c4cc41.yml -openapi_spec_hash: 48b4dfac35a842d7fb0d228caf87544e +openapi_spec_hash: 8a36f79075102c63234ed06107deb8c9 config_hash: 7386d24e2f03a3b2a89b3f6881446348 From fca12fdb5c55e38aafe17c8d41f0f0d1a888aadf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Feb 2026 07:05:47 +0000 Subject: [PATCH 103/164] chore(internal): upgrade AssertJ --- stagehand-java-client-okhttp/build.gradle.kts | 2 +- stagehand-java-core/build.gradle.kts | 2 +- stagehand-java-proguard-test/build.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stagehand-java-client-okhttp/build.gradle.kts b/stagehand-java-client-okhttp/build.gradle.kts index cb49933..49e7e71 100644 --- a/stagehand-java-client-okhttp/build.gradle.kts +++ b/stagehand-java-client-okhttp/build.gradle.kts @@ -10,6 +10,6 @@ dependencies { implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") testImplementation(kotlin("test")) - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") } diff --git a/stagehand-java-core/build.gradle.kts b/stagehand-java-core/build.gradle.kts index 3cfe35b..cd060e2 100644 --- a/stagehand-java-core/build.gradle.kts +++ b/stagehand-java-core/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(project(":stagehand-java-client-okhttp")) testImplementation("com.github.tomakehurst:wiremock-jre8:2.35.2") - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.3") testImplementation("org.junit-pioneer:junit-pioneer:1.9.1") diff --git a/stagehand-java-proguard-test/build.gradle.kts b/stagehand-java-proguard-test/build.gradle.kts index 1f6dfc6..0102d44 100644 --- a/stagehand-java-proguard-test/build.gradle.kts +++ b/stagehand-java-proguard-test/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { testImplementation(project(":stagehand-java")) testImplementation(kotlin("test")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.3") - testImplementation("org.assertj:assertj-core:3.25.3") + testImplementation("org.assertj:assertj-core:3.27.7") testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.0") } From 11137ca8fa958a6232bd764aa2e5ae07777f5e7d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 22:20:58 +0000 Subject: [PATCH 104/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index a0da57a..3eb04a2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8fbb3fa8f3a37c1c7408de427fe125aadec49f705e8e30d191601a9b69c4cc41.yml openapi_spec_hash: 8a36f79075102c63234ed06107deb8c9 -config_hash: 7386d24e2f03a3b2a89b3f6881446348 +config_hash: 4252fc025e947bc0fd6b2abd91a0cc8e From 52dbc22cee543a6164450971aeb3ff74f0f0d5d3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 01:46:16 +0000 Subject: [PATCH 105/164] =?UTF-8?q?feat:=20randomize=20region=20used=20for?= =?UTF-8?q?=20evals,=20split=20out=20pnpm=20and=20turbo=20cache,=20veri?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .stats.yml | 4 +- .../models/sessions/SessionReplayResponse.kt | 746 +++++++++++++++--- .../sessions/SessionReplayResponseTest.kt | 60 +- 3 files changed, 691 insertions(+), 119 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3eb04a2..27548de 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-8fbb3fa8f3a37c1c7408de427fe125aadec49f705e8e30d191601a9b69c4cc41.yml -openapi_spec_hash: 8a36f79075102c63234ed06107deb8c9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-5d0052068f044366d6d31570d9712922c9a80fdd6f9995af815e9afc075507ef.yml +openapi_spec_hash: c0cb787da075d8cd2d938c05b36b5efa config_hash: 4252fc025e947bc0fd6b2abd91a0cc8e diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt index 39ecafa..5ac9a0d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt @@ -195,19 +195,29 @@ private constructor( @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val pages: JsonField>, + private val clientLanguage: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("pages") @ExcludeMissing pages: JsonField> = JsonMissing.of() - ) : this(pages, mutableMapOf()) + @JsonProperty("pages") @ExcludeMissing pages: JsonField> = JsonMissing.of(), + @JsonProperty("clientLanguage") + @ExcludeMissing + clientLanguage: JsonField = JsonMissing.of(), + ) : this(pages, clientLanguage, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun pages(): List = pages.getRequired("pages") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun pages(): Optional> = pages.getOptional("pages") + fun clientLanguage(): Optional = clientLanguage.getOptional("clientLanguage") /** * Returns the raw JSON value of [pages]. @@ -216,6 +226,16 @@ private constructor( */ @JsonProperty("pages") @ExcludeMissing fun _pages(): JsonField> = pages + /** + * Returns the raw JSON value of [clientLanguage]. + * + * Unlike [clientLanguage], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("clientLanguage") + @ExcludeMissing + fun _clientLanguage(): JsonField = clientLanguage + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -230,7 +250,14 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Data]. */ + /** + * Returns a mutable builder for constructing an instance of [Data]. + * + * The following fields are required: + * ```java + * .pages() + * ``` + */ @JvmStatic fun builder() = Builder() } @@ -238,11 +265,13 @@ private constructor( class Builder internal constructor() { private var pages: JsonField>? = null + private var clientLanguage: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(data: Data) = apply { pages = data.pages.map { it.toMutableList() } + clientLanguage = data.clientLanguage additionalProperties = data.additionalProperties.toMutableMap() } @@ -271,6 +300,20 @@ private constructor( } } + fun clientLanguage(clientLanguage: String) = + clientLanguage(JsonField.of(clientLanguage)) + + /** + * Sets [Builder.clientLanguage] to an arbitrary JSON value. + * + * You should usually call [Builder.clientLanguage] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun clientLanguage(clientLanguage: JsonField) = apply { + this.clientLanguage = clientLanguage + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -294,10 +337,18 @@ private constructor( * Returns an immutable instance of [Data]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .pages() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): Data = Data( - (pages ?: JsonMissing.of()).map { it.toImmutable() }, + checkRequired("pages", pages).map { it.toImmutable() }, + clientLanguage, additionalProperties.toMutableMap(), ) } @@ -309,7 +360,8 @@ private constructor( return@apply } - pages().ifPresent { it.forEach { it.validate() } } + pages().forEach { it.validate() } + clientLanguage() validated = true } @@ -329,12 +381,16 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (pages.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (pages.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (clientLanguage.asKnown().isPresent) 1 else 0) class Page @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val actions: JsonField>, + private val duration: JsonField, + private val timestamp: JsonField, + private val url: JsonField, private val additionalProperties: MutableMap, ) { @@ -342,14 +398,43 @@ private constructor( private constructor( @JsonProperty("actions") @ExcludeMissing - actions: JsonField> = JsonMissing.of() - ) : this(actions, mutableMapOf()) + actions: JsonField> = JsonMissing.of(), + @JsonProperty("duration") + @ExcludeMissing + duration: JsonField = JsonMissing.of(), + @JsonProperty("timestamp") + @ExcludeMissing + timestamp: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(actions, duration, timestamp, url, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun actions(): List = actions.getRequired("actions") /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun actions(): Optional> = actions.getOptional("actions") + fun duration(): Double = duration.getRequired("duration") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun timestamp(): Double = timestamp.getRequired("timestamp") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun url(): String = url.getRequired("url") /** * Returns the raw JSON value of [actions]. @@ -360,6 +445,31 @@ private constructor( @ExcludeMissing fun _actions(): JsonField> = actions + /** + * Returns the raw JSON value of [duration]. + * + * Unlike [duration], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("duration") @ExcludeMissing fun _duration(): JsonField = duration + + /** + * Returns the raw JSON value of [timestamp]. + * + * Unlike [timestamp], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("timestamp") + @ExcludeMissing + fun _timestamp(): JsonField = timestamp + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -374,7 +484,17 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Page]. */ + /** + * Returns a mutable builder for constructing an instance of [Page]. + * + * The following fields are required: + * ```java + * .actions() + * .duration() + * .timestamp() + * .url() + * ``` + */ @JvmStatic fun builder() = Builder() } @@ -382,11 +502,17 @@ private constructor( class Builder internal constructor() { private var actions: JsonField>? = null + private var duration: JsonField? = null + private var timestamp: JsonField? = null + private var url: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(page: Page) = apply { actions = page.actions.map { it.toMutableList() } + duration = page.duration + timestamp = page.timestamp + url = page.url additionalProperties = page.additionalProperties.toMutableMap() } @@ -415,6 +541,39 @@ private constructor( } } + fun duration(duration: Double) = duration(JsonField.of(duration)) + + /** + * Sets [Builder.duration] to an arbitrary JSON value. + * + * You should usually call [Builder.duration] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun duration(duration: JsonField) = apply { this.duration = duration } + + fun timestamp(timestamp: Double) = timestamp(JsonField.of(timestamp)) + + /** + * Sets [Builder.timestamp] to an arbitrary JSON value. + * + * You should usually call [Builder.timestamp] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun timestamp(timestamp: JsonField) = apply { this.timestamp = timestamp } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun url(url: JsonField) = apply { this.url = url } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -441,10 +600,23 @@ private constructor( * Returns an immutable instance of [Page]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .actions() + * .duration() + * .timestamp() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): Page = Page( - (actions ?: JsonMissing.of()).map { it.toImmutable() }, + checkRequired("actions", actions).map { it.toImmutable() }, + checkRequired("duration", duration), + checkRequired("timestamp", timestamp), + checkRequired("url", url), additionalProperties.toMutableMap(), ) } @@ -456,7 +628,10 @@ private constructor( return@apply } - actions().ifPresent { it.forEach { it.validate() } } + actions().forEach { it.validate() } + duration() + timestamp() + url() validated = true } @@ -476,12 +651,19 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + (actions.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (duration.asKnown().isPresent) 1 else 0) + + (if (timestamp.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) class Action @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val method: JsonField, + private val parameters: JsonField, + private val result: JsonField, + private val timestamp: JsonField, + private val endTime: JsonField, private val tokenUsage: JsonField, private val additionalProperties: MutableMap, ) { @@ -491,16 +673,56 @@ private constructor( @JsonProperty("method") @ExcludeMissing method: JsonField = JsonMissing.of(), + @JsonProperty("parameters") + @ExcludeMissing + parameters: JsonField = JsonMissing.of(), + @JsonProperty("result") + @ExcludeMissing + result: JsonField = JsonMissing.of(), + @JsonProperty("timestamp") + @ExcludeMissing + timestamp: JsonField = JsonMissing.of(), + @JsonProperty("endTime") + @ExcludeMissing + endTime: JsonField = JsonMissing.of(), @JsonProperty("tokenUsage") @ExcludeMissing tokenUsage: JsonField = JsonMissing.of(), - ) : this(method, tokenUsage, mutableMapOf()) + ) : this(method, parameters, result, timestamp, endTime, tokenUsage, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun method(): String = method.getRequired("method") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun parameters(): Parameters = parameters.getRequired("parameters") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun result(): Result = result.getRequired("result") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun timestamp(): Double = timestamp.getRequired("timestamp") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). */ - fun method(): Optional = method.getOptional("method") + fun endTime(): Optional = endTime.getOptional("endTime") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type @@ -516,6 +738,42 @@ private constructor( */ @JsonProperty("method") @ExcludeMissing fun _method(): JsonField = method + /** + * Returns the raw JSON value of [parameters]. + * + * Unlike [parameters], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("parameters") + @ExcludeMissing + fun _parameters(): JsonField = parameters + + /** + * Returns the raw JSON value of [result]. + * + * Unlike [result], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("result") @ExcludeMissing fun _result(): JsonField = result + + /** + * Returns the raw JSON value of [timestamp]. + * + * Unlike [timestamp], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("timestamp") + @ExcludeMissing + fun _timestamp(): JsonField = timestamp + + /** + * Returns the raw JSON value of [endTime]. + * + * Unlike [endTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("endTime") @ExcludeMissing fun _endTime(): JsonField = endTime + /** * Returns the raw JSON value of [tokenUsage]. * @@ -540,20 +798,38 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Action]. */ + /** + * Returns a mutable builder for constructing an instance of [Action]. + * + * The following fields are required: + * ```java + * .method() + * .parameters() + * .result() + * .timestamp() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [Action]. */ class Builder internal constructor() { - private var method: JsonField = JsonMissing.of() + private var method: JsonField? = null + private var parameters: JsonField? = null + private var result: JsonField? = null + private var timestamp: JsonField? = null + private var endTime: JsonField = JsonMissing.of() private var tokenUsage: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(action: Action) = apply { method = action.method + parameters = action.parameters + result = action.result + timestamp = action.timestamp + endTime = action.endTime tokenUsage = action.tokenUsage additionalProperties = action.additionalProperties.toMutableMap() } @@ -569,6 +845,54 @@ private constructor( */ fun method(method: JsonField) = apply { this.method = method } + fun parameters(parameters: Parameters) = parameters(JsonField.of(parameters)) + + /** + * Sets [Builder.parameters] to an arbitrary JSON value. + * + * You should usually call [Builder.parameters] with a well-typed [Parameters] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun parameters(parameters: JsonField) = apply { + this.parameters = parameters + } + + fun result(result: Result) = result(JsonField.of(result)) + + /** + * Sets [Builder.result] to an arbitrary JSON value. + * + * You should usually call [Builder.result] with a well-typed [Result] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun result(result: JsonField) = apply { this.result = result } + + fun timestamp(timestamp: Double) = timestamp(JsonField.of(timestamp)) + + /** + * Sets [Builder.timestamp] to an arbitrary JSON value. + * + * You should usually call [Builder.timestamp] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun timestamp(timestamp: JsonField) = apply { + this.timestamp = timestamp + } + + fun endTime(endTime: Double) = endTime(JsonField.of(endTime)) + + /** + * Sets [Builder.endTime] to an arbitrary JSON value. + * + * You should usually call [Builder.endTime] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun endTime(endTime: JsonField) = apply { this.endTime = endTime } + fun tokenUsage(tokenUsage: TokenUsage) = tokenUsage(JsonField.of(tokenUsage)) /** @@ -608,9 +932,27 @@ private constructor( * Returns an immutable instance of [Action]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .method() + * .parameters() + * .result() + * .timestamp() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): Action = - Action(method, tokenUsage, additionalProperties.toMutableMap()) + Action( + checkRequired("method", method), + checkRequired("parameters", parameters), + checkRequired("result", result), + checkRequired("timestamp", timestamp), + endTime, + tokenUsage, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -621,6 +963,10 @@ private constructor( } method() + parameters().validate() + result().validate() + timestamp() + endTime() tokenUsage().ifPresent { it.validate() } validated = true } @@ -642,51 +988,257 @@ private constructor( @JvmSynthetic internal fun validity(): Int = (if (method.asKnown().isPresent) 1 else 0) + + (parameters.asKnown().getOrNull()?.validity() ?: 0) + + (result.asKnown().getOrNull()?.validity() ?: 0) + + (if (timestamp.asKnown().isPresent) 1 else 0) + + (if (endTime.asKnown().isPresent) 1 else 0) + (tokenUsage.asKnown().getOrNull()?.validity() ?: 0) + class Parameters + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Parameters]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Parameters]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(parameters: Parameters) = apply { + additionalProperties = parameters.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Parameters]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Parameters = Parameters(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Parameters = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Parameters && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Parameters{additionalProperties=$additionalProperties}" + } + + class Result + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Result]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Result]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(result: Result) = apply { + additionalProperties = result.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Result]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Result = Result(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Result = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Result && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Result{additionalProperties=$additionalProperties}" + } + class TokenUsage @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val cachedInputTokens: JsonField, + private val cost: JsonField, private val inputTokens: JsonField, private val outputTokens: JsonField, - private val reasoningTokens: JsonField, private val timeMs: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("cachedInputTokens") + @JsonProperty("cost") @ExcludeMissing - cachedInputTokens: JsonField = JsonMissing.of(), + cost: JsonField = JsonMissing.of(), @JsonProperty("inputTokens") @ExcludeMissing inputTokens: JsonField = JsonMissing.of(), @JsonProperty("outputTokens") @ExcludeMissing outputTokens: JsonField = JsonMissing.of(), - @JsonProperty("reasoningTokens") - @ExcludeMissing - reasoningTokens: JsonField = JsonMissing.of(), @JsonProperty("timeMs") @ExcludeMissing timeMs: JsonField = JsonMissing.of(), - ) : this( - cachedInputTokens, - inputTokens, - outputTokens, - reasoningTokens, - timeMs, - mutableMapOf(), - ) + ) : this(cost, inputTokens, outputTokens, timeMs, mutableMapOf()) /** * @throws StagehandInvalidDataException if the JSON field has an unexpected * type (e.g. if the server responded with an unexpected value). */ - fun cachedInputTokens(): Optional = - cachedInputTokens.getOptional("cachedInputTokens") + fun cost(): Optional = cost.getOptional("cost") /** * @throws StagehandInvalidDataException if the JSON field has an unexpected @@ -700,13 +1252,6 @@ private constructor( */ fun outputTokens(): Optional = outputTokens.getOptional("outputTokens") - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun reasoningTokens(): Optional = - reasoningTokens.getOptional("reasoningTokens") - /** * @throws StagehandInvalidDataException if the JSON field has an unexpected * type (e.g. if the server responded with an unexpected value). @@ -714,14 +1259,12 @@ private constructor( fun timeMs(): Optional = timeMs.getOptional("timeMs") /** - * Returns the raw JSON value of [cachedInputTokens]. + * Returns the raw JSON value of [cost]. * - * Unlike [cachedInputTokens], this method doesn't throw if the JSON field has - * an unexpected type. + * Unlike [cost], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("cachedInputTokens") - @ExcludeMissing - fun _cachedInputTokens(): JsonField = cachedInputTokens + @JsonProperty("cost") @ExcludeMissing fun _cost(): JsonField = cost /** * Returns the raw JSON value of [inputTokens]. @@ -743,16 +1286,6 @@ private constructor( @ExcludeMissing fun _outputTokens(): JsonField = outputTokens - /** - * Returns the raw JSON value of [reasoningTokens]. - * - * Unlike [reasoningTokens], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("reasoningTokens") - @ExcludeMissing - fun _reasoningTokens(): JsonField = reasoningTokens - /** * Returns the raw JSON value of [timeMs]. * @@ -786,37 +1319,32 @@ private constructor( /** A builder for [TokenUsage]. */ class Builder internal constructor() { - private var cachedInputTokens: JsonField = JsonMissing.of() + private var cost: JsonField = JsonMissing.of() private var inputTokens: JsonField = JsonMissing.of() private var outputTokens: JsonField = JsonMissing.of() - private var reasoningTokens: JsonField = JsonMissing.of() private var timeMs: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(tokenUsage: TokenUsage) = apply { - cachedInputTokens = tokenUsage.cachedInputTokens + cost = tokenUsage.cost inputTokens = tokenUsage.inputTokens outputTokens = tokenUsage.outputTokens - reasoningTokens = tokenUsage.reasoningTokens timeMs = tokenUsage.timeMs additionalProperties = tokenUsage.additionalProperties.toMutableMap() } - fun cachedInputTokens(cachedInputTokens: Double) = - cachedInputTokens(JsonField.of(cachedInputTokens)) + fun cost(cost: Double) = cost(JsonField.of(cost)) /** - * Sets [Builder.cachedInputTokens] to an arbitrary JSON value. + * Sets [Builder.cost] to an arbitrary JSON value. * - * You should usually call [Builder.cachedInputTokens] with a well-typed - * [Double] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. + * You should usually call [Builder.cost] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. */ - fun cachedInputTokens(cachedInputTokens: JsonField) = apply { - this.cachedInputTokens = cachedInputTokens - } + fun cost(cost: JsonField) = apply { this.cost = cost } fun inputTokens(inputTokens: Double) = inputTokens(JsonField.of(inputTokens)) @@ -846,20 +1374,6 @@ private constructor( this.outputTokens = outputTokens } - fun reasoningTokens(reasoningTokens: Double) = - reasoningTokens(JsonField.of(reasoningTokens)) - - /** - * Sets [Builder.reasoningTokens] to an arbitrary JSON value. - * - * You should usually call [Builder.reasoningTokens] with a well-typed - * [Double] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. - */ - fun reasoningTokens(reasoningTokens: JsonField) = apply { - this.reasoningTokens = reasoningTokens - } - fun timeMs(timeMs: Double) = timeMs(JsonField.of(timeMs)) /** @@ -900,10 +1414,9 @@ private constructor( */ fun build(): TokenUsage = TokenUsage( - cachedInputTokens, + cost, inputTokens, outputTokens, - reasoningTokens, timeMs, additionalProperties.toMutableMap(), ) @@ -916,10 +1429,9 @@ private constructor( return@apply } - cachedInputTokens() + cost() inputTokens() outputTokens() - reasoningTokens() timeMs() validated = true } @@ -940,10 +1452,9 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (cachedInputTokens.asKnown().isPresent) 1 else 0) + + (if (cost.asKnown().isPresent) 1 else 0) + (if (inputTokens.asKnown().isPresent) 1 else 0) + (if (outputTokens.asKnown().isPresent) 1 else 0) + - (if (reasoningTokens.asKnown().isPresent) 1 else 0) + (if (timeMs.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -952,29 +1463,21 @@ private constructor( } return other is TokenUsage && - cachedInputTokens == other.cachedInputTokens && + cost == other.cost && inputTokens == other.inputTokens && outputTokens == other.outputTokens && - reasoningTokens == other.reasoningTokens && timeMs == other.timeMs && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash( - cachedInputTokens, - inputTokens, - outputTokens, - reasoningTokens, - timeMs, - additionalProperties, - ) + Objects.hash(cost, inputTokens, outputTokens, timeMs, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "TokenUsage{cachedInputTokens=$cachedInputTokens, inputTokens=$inputTokens, outputTokens=$outputTokens, reasoningTokens=$reasoningTokens, timeMs=$timeMs, additionalProperties=$additionalProperties}" + "TokenUsage{cost=$cost, inputTokens=$inputTokens, outputTokens=$outputTokens, timeMs=$timeMs, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -984,18 +1487,30 @@ private constructor( return other is Action && method == other.method && + parameters == other.parameters && + result == other.result && + timestamp == other.timestamp && + endTime == other.endTime && tokenUsage == other.tokenUsage && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(method, tokenUsage, additionalProperties) + Objects.hash( + method, + parameters, + result, + timestamp, + endTime, + tokenUsage, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "Action{method=$method, tokenUsage=$tokenUsage, additionalProperties=$additionalProperties}" + "Action{method=$method, parameters=$parameters, result=$result, timestamp=$timestamp, endTime=$endTime, tokenUsage=$tokenUsage, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1005,15 +1520,20 @@ private constructor( return other is Page && actions == other.actions && + duration == other.duration && + timestamp == other.timestamp && + url == other.url && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(actions, additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash(actions, duration, timestamp, url, additionalProperties) + } override fun hashCode(): Int = hashCode override fun toString() = - "Page{actions=$actions, additionalProperties=$additionalProperties}" + "Page{actions=$actions, duration=$duration, timestamp=$timestamp, url=$url, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1023,14 +1543,18 @@ private constructor( return other is Data && pages == other.pages && + clientLanguage == other.clientLanguage && additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(pages, additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash(pages, clientLanguage, additionalProperties) + } override fun hashCode(): Int = hashCode - override fun toString() = "Data{pages=$pages, additionalProperties=$additionalProperties}" + override fun toString() = + "Data{pages=$pages, clientLanguage=$clientLanguage, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt index 848c7f7..0c0e456 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionReplayResponseTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat @@ -20,20 +21,36 @@ internal class SessionReplayResponseTest { .addAction( SessionReplayResponse.Data.Page.Action.builder() .method("method") + .parameters( + SessionReplayResponse.Data.Page.Action.Parameters + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .result( + SessionReplayResponse.Data.Page.Action.Result.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .timestamp(0.0) + .endTime(0.0) .tokenUsage( SessionReplayResponse.Data.Page.Action.TokenUsage .builder() - .cachedInputTokens(0.0) + .cost(0.0) .inputTokens(0.0) .outputTokens(0.0) - .reasoningTokens(0.0) .timeMs(0.0) .build() ) .build() ) + .duration(0.0) + .timestamp(0.0) + .url("url") .build() ) + .clientLanguage("clientLanguage") .build() ) .success(true) @@ -47,19 +64,34 @@ internal class SessionReplayResponseTest { .addAction( SessionReplayResponse.Data.Page.Action.builder() .method("method") + .parameters( + SessionReplayResponse.Data.Page.Action.Parameters.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .result( + SessionReplayResponse.Data.Page.Action.Result.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .timestamp(0.0) + .endTime(0.0) .tokenUsage( SessionReplayResponse.Data.Page.Action.TokenUsage.builder() - .cachedInputTokens(0.0) + .cost(0.0) .inputTokens(0.0) .outputTokens(0.0) - .reasoningTokens(0.0) .timeMs(0.0) .build() ) .build() ) + .duration(0.0) + .timestamp(0.0) + .url("url") .build() ) + .clientLanguage("clientLanguage") .build() ) assertThat(sessionReplayResponse.success()).isEqualTo(true) @@ -77,20 +109,36 @@ internal class SessionReplayResponseTest { .addAction( SessionReplayResponse.Data.Page.Action.builder() .method("method") + .parameters( + SessionReplayResponse.Data.Page.Action.Parameters + .builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .result( + SessionReplayResponse.Data.Page.Action.Result.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .timestamp(0.0) + .endTime(0.0) .tokenUsage( SessionReplayResponse.Data.Page.Action.TokenUsage .builder() - .cachedInputTokens(0.0) + .cost(0.0) .inputTokens(0.0) .outputTokens(0.0) - .reasoningTokens(0.0) .timeMs(0.0) .build() ) .build() ) + .duration(0.0) + .timestamp(0.0) + .url("url") .build() ) + .clientLanguage("clientLanguage") .build() ) .success(true) From a75288a9a732befcf6ebdc82ad303991f6b556a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Feb 2026 04:51:54 +0000 Subject: [PATCH 106/164] chore(internal): update `TestServerExtension` comment --- .../com/browserbase/api/TestServerExtension.kt | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt index d83abd1..59f0170 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt @@ -15,25 +15,12 @@ class TestServerExtension : BeforeAllCallback, ExecutionCondition { } catch (e: Exception) { throw RuntimeException( """ - The test suite will not run without a mock Prism server running against your OpenAPI spec. + The test suite will not run without a mock server running against your OpenAPI spec. You can set the environment variable `SKIP_MOCK_TESTS` to `true` to skip running any tests that require the mock server. - To fix: - - 1. Install Prism (requires Node 16+): - - With npm: - $ npm install -g @stoplight/prism-cli - - With yarn: - $ yarn global add @stoplight/prism-cli - - 2. Run the mock server - - To run the server, pass in the path of your OpenAPI spec to the prism command: - $ prism mock path/to/your.openapi.yml + To fix run `./scripts/mock` in a separate terminal. """ .trimIndent(), e, From b04e1b9e03b38e2078ff1e68570c4aea484250fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 04:48:46 +0000 Subject: [PATCH 107/164] chore(internal): make `OkHttp` constructor internal --- .../kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index dadd500..238d21d 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -33,7 +33,7 @@ import okhttp3.logging.HttpLoggingInterceptor import okio.BufferedSink class OkHttpClient -private constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { +internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { val call = newCall(request, requestOptions) From 90774dda7ebf7b378f841e57cfb0ff784ac50a09 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 04:52:33 +0000 Subject: [PATCH 108/164] feat(client): add connection pooling option --- README.md | 19 ++++++++ .../api/client/okhttp/OkHttpClient.kt | 42 ++++++++++++++++++ .../client/okhttp/StagehandOkHttpClient.kt | 44 +++++++++++++++++++ .../okhttp/StagehandOkHttpClientAsync.kt | 44 +++++++++++++++++++ 4 files changed, 149 insertions(+) diff --git a/README.md b/README.md index 4d35164..7a37f08 100644 --- a/README.md +++ b/README.md @@ -450,6 +450,25 @@ StagehandClient client = StagehandOkHttpClient.builder() .build(); ``` +### Connection pooling + +To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods: + +```java +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; +import java.time.Duration; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa. + .maxIdleConnections(10) + .keepAliveDuration(Duration.ofMinutes(2)) + .build(); +``` + +If both options are unset, OkHttp's default connection pool settings are used. + ### HTTPS > [!NOTE] diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index 238d21d..688abb6 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -16,11 +16,13 @@ import java.time.Duration import java.util.concurrent.CancellationException import java.util.concurrent.CompletableFuture import java.util.concurrent.ExecutorService +import java.util.concurrent.TimeUnit import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager import okhttp3.Call import okhttp3.Callback +import okhttp3.ConnectionPool import okhttp3.Dispatcher import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType @@ -204,6 +206,8 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var maxIdleConnections: Int? = null + private var keepAliveDuration: Duration? = null private var dispatcherExecutorService: ExecutorService? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null @@ -215,6 +219,28 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + /** + * Sets the maximum number of idle connections kept by the underlying [ConnectionPool]. + * + * If this is set, then [keepAliveDuration] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun maxIdleConnections(maxIdleConnections: Int?) = apply { + this.maxIdleConnections = maxIdleConnections + } + + /** + * Sets the keep-alive duration for idle connections in the underlying [ConnectionPool]. + * + * If this is set, then [maxIdleConnections] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun keepAliveDuration(keepAliveDuration: Duration?) = apply { + this.keepAliveDuration = keepAliveDuration + } + fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply { this.dispatcherExecutorService = dispatcherExecutorService } @@ -244,6 +270,22 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie .apply { dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } + val maxIdleConnections = maxIdleConnections + val keepAliveDuration = keepAliveDuration + if (maxIdleConnections != null && keepAliveDuration != null) { + connectionPool( + ConnectionPool( + maxIdleConnections, + keepAliveDuration.toNanos(), + TimeUnit.NANOSECONDS, + ) + ) + } else { + check((maxIdleConnections != null) == (keepAliveDuration != null)) { + "Both or none of `maxIdleConnections` and `keepAliveDuration` must be set, but only one was set" + } + } + val sslSocketFactory = sslSocketFactory val trustManager = trustManager if (sslSocketFactory != null && trustManager != null) { diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index f5d6ff5..2137ec6 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -49,6 +49,8 @@ class StagehandOkHttpClient private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null + private var maxIdleConnections: Int? = null + private var keepAliveDuration: Duration? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -77,6 +79,46 @@ class StagehandOkHttpClient private constructor() { /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + /** + * The maximum number of idle connections kept by the underlying OkHttp connection pool. + * + * If this is set, then [keepAliveDuration] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun maxIdleConnections(maxIdleConnections: Int?) = apply { + this.maxIdleConnections = maxIdleConnections + } + + /** + * Alias for [Builder.maxIdleConnections]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun maxIdleConnections(maxIdleConnections: Int) = + maxIdleConnections(maxIdleConnections as Int?) + + /** + * Alias for calling [Builder.maxIdleConnections] with `maxIdleConnections.orElse(null)`. + */ + fun maxIdleConnections(maxIdleConnections: Optional) = + maxIdleConnections(maxIdleConnections.getOrNull()) + + /** + * The keep-alive duration for idle connections in the underlying OkHttp connection pool. + * + * If this is set, then [maxIdleConnections] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun keepAliveDuration(keepAliveDuration: Duration?) = apply { + this.keepAliveDuration = keepAliveDuration + } + + /** Alias for calling [Builder.keepAliveDuration] with `keepAliveDuration.orElse(null)`. */ + fun keepAliveDuration(keepAliveDuration: Optional) = + keepAliveDuration(keepAliveDuration.getOrNull()) + /** * The socket factory used to secure HTTPS connections. * @@ -341,6 +383,8 @@ class StagehandOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .maxIdleConnections(maxIdleConnections) + .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 9f8bbb7..ffacd17 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -49,6 +49,8 @@ class StagehandOkHttpClientAsync private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null + private var maxIdleConnections: Int? = null + private var keepAliveDuration: Duration? = null private var sslSocketFactory: SSLSocketFactory? = null private var trustManager: X509TrustManager? = null private var hostnameVerifier: HostnameVerifier? = null @@ -77,6 +79,46 @@ class StagehandOkHttpClientAsync private constructor() { /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + /** + * The maximum number of idle connections kept by the underlying OkHttp connection pool. + * + * If this is set, then [keepAliveDuration] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun maxIdleConnections(maxIdleConnections: Int?) = apply { + this.maxIdleConnections = maxIdleConnections + } + + /** + * Alias for [Builder.maxIdleConnections]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun maxIdleConnections(maxIdleConnections: Int) = + maxIdleConnections(maxIdleConnections as Int?) + + /** + * Alias for calling [Builder.maxIdleConnections] with `maxIdleConnections.orElse(null)`. + */ + fun maxIdleConnections(maxIdleConnections: Optional) = + maxIdleConnections(maxIdleConnections.getOrNull()) + + /** + * The keep-alive duration for idle connections in the underlying OkHttp connection pool. + * + * If this is set, then [maxIdleConnections] must also be set. + * + * If unset, then OkHttp's default is used. + */ + fun keepAliveDuration(keepAliveDuration: Duration?) = apply { + this.keepAliveDuration = keepAliveDuration + } + + /** Alias for calling [Builder.keepAliveDuration] with `keepAliveDuration.orElse(null)`. */ + fun keepAliveDuration(keepAliveDuration: Optional) = + keepAliveDuration(keepAliveDuration.getOrNull()) + /** * The socket factory used to secure HTTPS connections. * @@ -341,6 +383,8 @@ class StagehandOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .maxIdleConnections(maxIdleConnections) + .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) .sslSocketFactory(sslSocketFactory) .trustManager(trustManager) From e0b5bd39b3b174336d57c3c8cf80957c4f6f5262 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:29:45 +0000 Subject: [PATCH 109/164] feat: Multi-region stagehand api support --- .stats.yml | 6 +++--- buildSrc/src/main/kotlin/stagehand.publish.gradle.kts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 27548de..ea1fdd4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-5d0052068f044366d6d31570d9712922c9a80fdd6f9995af815e9afc075507ef.yml -openapi_spec_hash: c0cb787da075d8cd2d938c05b36b5efa -config_hash: 4252fc025e947bc0fd6b2abd91a0cc8e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-6fd391f729eb05dc7b6168adff89e6198bc545ebd4ff737494d72288870e0977.yml +openapi_spec_hash: ee16862542659f47acc8dcd5669c7623 +config_hash: 7386d24e2f03a3b2a89b3f6881446348 diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index f45a9d7..a24d7f5 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -43,7 +43,7 @@ configure { pom { name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\n## Multi-Region Support\n\nThe Stagehand API is available in multiple regions. Choose the API endpoint that\nmatches where your browser session is running:\n\n| Region | Endpoint |\n| ------------------- | ------------------------------------------- |\n| us-west-2 (default) | https://api.stagehand.browserbase.com |\n| us-east-1 | https://api.use1.stagehand.browserbase.com |\n| eu-central-1 | https://api.euc1.stagehand.browserbase.com |\n| ap-southeast-1 | https://api.apse1.stagehand.browserbase.com |\n\n**Important:** The API endpoint must match your browser session region. If\nthere's a mismatch, you'll receive a BAD_REQUEST error:\n`Session is in region 'X' but this API instance serves 'Y'. Please route your request to the X Stagehand API endpoint.`\n\nTo disable API mode and use local browser automation, set `disableAPI: true` in\nyour Stagehand configuration.\n\n## Authentication and Usage\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") url.set("https://docs.stagehand.dev") licenses { From 62b2c9af007e0daecdc746763f37b17b7479cded Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 05:43:25 +0000 Subject: [PATCH 110/164] chore(internal): remove mock server code --- scripts/mock | 41 ---------------- scripts/test | 46 ----------------- .../browserbase/api/TestServerExtension.kt | 49 ------------------- .../services/async/SessionServiceAsyncTest.kt | 15 ------ .../services/blocking/SessionServiceTest.kt | 15 ------ 5 files changed, 166 deletions(-) delete mode 100755 scripts/mock delete mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt diff --git a/scripts/mock b/scripts/mock deleted file mode 100755 index 0b28f6e..0000000 --- a/scripts/mock +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -if [[ -n "$1" && "$1" != '--'* ]]; then - URL="$1" - shift -else - URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" -fi - -# Check if the URL is empty -if [ -z "$URL" ]; then - echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" - exit 1 -fi - -echo "==> Starting mock server with URL ${URL}" - -# Run prism mock on the given spec -if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - - # Wait for server to come online - echo -n "Waiting for server" - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do - echo -n "." - sleep 0.1 - done - - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - - echo -else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" -fi diff --git a/scripts/test b/scripts/test index 047bc1d..904aea6 100755 --- a/scripts/test +++ b/scripts/test @@ -4,53 +4,7 @@ set -e cd "$(dirname "$0")/.." -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 -} - -kill_server_on_port() { - pids=$(lsof -t -i tcp:"$1" || echo "") - if [ "$pids" != "" ]; then - kill "$pids" - echo "Stopped $pids." - fi -} - -function is_overriding_api_base_url() { - [ -n "$TEST_API_BASE_URL" ] -} - -if ! is_overriding_api_base_url && ! prism_is_running ; then - # When we exit this script, make sure to kill the background mock server process - trap 'kill_server_on_port 4010' EXIT - - # Start the dev server - ./scripts/mock --daemon -fi - -if is_overriding_api_base_url ; then - echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" - echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" - echo -e "running against your OpenAPI spec." - echo - echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" - echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" - echo - - exit 1 -else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" - echo -fi echo "==> Running tests" ./gradlew test "$@" diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt deleted file mode 100644 index 59f0170..0000000 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/TestServerExtension.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.browserbase.api - -import java.lang.RuntimeException -import java.net.URL -import org.junit.jupiter.api.extension.BeforeAllCallback -import org.junit.jupiter.api.extension.ConditionEvaluationResult -import org.junit.jupiter.api.extension.ExecutionCondition -import org.junit.jupiter.api.extension.ExtensionContext - -class TestServerExtension : BeforeAllCallback, ExecutionCondition { - - override fun beforeAll(context: ExtensionContext?) { - try { - URL(BASE_URL).openConnection().connect() - } catch (e: Exception) { - throw RuntimeException( - """ - The test suite will not run without a mock server running against your OpenAPI spec. - - You can set the environment variable `SKIP_MOCK_TESTS` to `true` to skip running any tests - that require the mock server. - - To fix run `./scripts/mock` in a separate terminal. - """ - .trimIndent(), - e, - ) - } - } - - override fun evaluateExecutionCondition(context: ExtensionContext): ConditionEvaluationResult { - return if (System.getenv(SKIP_TESTS_ENV).toBoolean()) { - ConditionEvaluationResult.disabled( - "Environment variable $SKIP_TESTS_ENV is set to true" - ) - } else { - ConditionEvaluationResult.enabled( - "Environment variable $SKIP_TESTS_ENV is not set to true" - ) - } - } - - companion object { - - val BASE_URL = System.getenv("TEST_API_BASE_URL") ?: "http://localhost:4010" - - const val SKIP_TESTS_ENV: String = "SKIP_MOCK_TESTS" - } -} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 889335e..3b5ecb6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -2,7 +2,6 @@ package com.browserbase.api.services.async -import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClientAsync import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.ModelConfig @@ -16,9 +15,7 @@ import com.browserbase.api.models.sessions.SessionReplayParams import com.browserbase.api.models.sessions.SessionStartParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class SessionServiceAsyncTest { @Disabled("Prism tests are disabled") @@ -26,7 +23,6 @@ internal class SessionServiceAsyncTest { fun act() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -70,7 +66,6 @@ internal class SessionServiceAsyncTest { fun actStreaming() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -115,7 +110,6 @@ internal class SessionServiceAsyncTest { fun end() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -139,7 +133,6 @@ internal class SessionServiceAsyncTest { fun execute() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -198,7 +191,6 @@ internal class SessionServiceAsyncTest { fun executeStreaming() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -258,7 +250,6 @@ internal class SessionServiceAsyncTest { fun extract() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -303,7 +294,6 @@ internal class SessionServiceAsyncTest { fun extractStreaming() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -349,7 +339,6 @@ internal class SessionServiceAsyncTest { fun navigate() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -383,7 +372,6 @@ internal class SessionServiceAsyncTest { fun observe() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -423,7 +411,6 @@ internal class SessionServiceAsyncTest { fun observeStreaming() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -464,7 +451,6 @@ internal class SessionServiceAsyncTest { fun replay() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -488,7 +474,6 @@ internal class SessionServiceAsyncTest { fun start() { val client = StagehandOkHttpClientAsync.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index d9c3ea3..c41b6c4 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -2,7 +2,6 @@ package com.browserbase.api.services.blocking -import com.browserbase.api.TestServerExtension import com.browserbase.api.client.okhttp.StagehandOkHttpClient import com.browserbase.api.core.JsonValue import com.browserbase.api.models.sessions.ModelConfig @@ -16,9 +15,7 @@ import com.browserbase.api.models.sessions.SessionReplayParams import com.browserbase.api.models.sessions.SessionStartParams import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -@ExtendWith(TestServerExtension::class) internal class SessionServiceTest { @Disabled("Prism tests are disabled") @@ -26,7 +23,6 @@ internal class SessionServiceTest { fun act() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -69,7 +65,6 @@ internal class SessionServiceTest { fun actStreaming() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -114,7 +109,6 @@ internal class SessionServiceTest { fun end() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -137,7 +131,6 @@ internal class SessionServiceTest { fun execute() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -195,7 +188,6 @@ internal class SessionServiceTest { fun executeStreaming() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -255,7 +247,6 @@ internal class SessionServiceTest { fun extract() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -299,7 +290,6 @@ internal class SessionServiceTest { fun extractStreaming() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -345,7 +335,6 @@ internal class SessionServiceTest { fun navigate() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -378,7 +367,6 @@ internal class SessionServiceTest { fun observe() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -417,7 +405,6 @@ internal class SessionServiceTest { fun observeStreaming() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -458,7 +445,6 @@ internal class SessionServiceTest { fun replay() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") @@ -481,7 +467,6 @@ internal class SessionServiceTest { fun start() { val client = StagehandOkHttpClient.builder() - .baseUrl(TestServerExtension.BASE_URL) .browserbaseApiKey("My Browserbase API Key") .browserbaseProjectId("My Browserbase Project ID") .modelApiKey("My Model API Key") From fda81ab781d6b9ce6fb38c17a7411072f4897e1f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 05:44:19 +0000 Subject: [PATCH 111/164] chore: update mock server docs --- .../api/services/ServiceParamsTest.kt | 4 ++-- .../services/async/SessionServiceAsyncTest.kt | 24 +++++++++---------- .../services/blocking/SessionServiceTest.kt | 24 +++++++++---------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 61376c2..f3a40b7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -40,7 +40,7 @@ internal class ServiceParamsTest { .build() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun start() { val sessionService = client.sessions() @@ -205,7 +205,7 @@ internal class ServiceParamsTest { ) } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun act() { val sessionService = client.sessions() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 3b5ecb6..2a0e601 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -18,7 +18,7 @@ import org.junit.jupiter.api.Test internal class SessionServiceAsyncTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun act() { val client = @@ -61,7 +61,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun actStreaming() { val client = @@ -105,7 +105,7 @@ internal class SessionServiceAsyncTest { onCompleteFuture.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun end() { val client = @@ -128,7 +128,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun execute() { val client = @@ -186,7 +186,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun executeStreaming() { val client = @@ -245,7 +245,7 @@ internal class SessionServiceAsyncTest { onCompleteFuture.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun extract() { val client = @@ -289,7 +289,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun extractStreaming() { val client = @@ -334,7 +334,7 @@ internal class SessionServiceAsyncTest { onCompleteFuture.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun navigate() { val client = @@ -367,7 +367,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun observe() { val client = @@ -406,7 +406,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun observeStreaming() { val client = @@ -446,7 +446,7 @@ internal class SessionServiceAsyncTest { onCompleteFuture.get() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun replay() { val client = @@ -469,7 +469,7 @@ internal class SessionServiceAsyncTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun start() { val client = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index c41b6c4..dedab31 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -18,7 +18,7 @@ import org.junit.jupiter.api.Test internal class SessionServiceTest { - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun act() { val client = @@ -60,7 +60,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun actStreaming() { val client = @@ -104,7 +104,7 @@ internal class SessionServiceTest { } } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun end() { val client = @@ -126,7 +126,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun execute() { val client = @@ -183,7 +183,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun executeStreaming() { val client = @@ -242,7 +242,7 @@ internal class SessionServiceTest { } } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun extract() { val client = @@ -285,7 +285,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun extractStreaming() { val client = @@ -330,7 +330,7 @@ internal class SessionServiceTest { } } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun navigate() { val client = @@ -362,7 +362,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun observe() { val client = @@ -400,7 +400,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun observeStreaming() { val client = @@ -440,7 +440,7 @@ internal class SessionServiceTest { } } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun replay() { val client = @@ -462,7 +462,7 @@ internal class SessionServiceTest { response.validate() } - @Disabled("Prism tests are disabled") + @Disabled("Mock server tests are disabled") @Test fun start() { val client = From fee79749939e532e83ad0ed41d6403f5bdf98303 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 06:08:58 +0000 Subject: [PATCH 112/164] chore: make `Properties` more resilient to `null` --- .../src/main/kotlin/com/browserbase/api/core/Properties.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt index c14d552..936e15a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Properties.kt @@ -34,9 +34,9 @@ fun getOsName(): String { } } -fun getOsVersion(): String = System.getProperty("os.version", "unknown") +fun getOsVersion(): String = System.getProperty("os.version", "unknown") ?: "unknown" fun getPackageVersion(): String = - StagehandClient::class.java.`package`.implementationVersion ?: "unknown" + StagehandClient::class.java.`package`?.implementationVersion ?: "unknown" -fun getJavaVersion(): String = System.getProperty("java.version", "unknown") +fun getJavaVersion(): String = System.getProperty("java.version", "unknown") ?: "unknown" From aa51214a2279ebc2b4de42a61fc051e7fc3050fc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 06:10:50 +0000 Subject: [PATCH 113/164] chore: drop apache dependency --- stagehand-java-core/build.gradle.kts | 2 - .../api/core/http/HttpRequestBodies.kt | 297 +++++-- .../api/core/http/HttpRequestBodiesTest.kt | 729 ++++++++++++++++++ 3 files changed, 946 insertions(+), 82 deletions(-) create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestBodiesTest.kt diff --git a/stagehand-java-core/build.gradle.kts b/stagehand-java-core/build.gradle.kts index cd060e2..55e80f4 100644 --- a/stagehand-java-core/build.gradle.kts +++ b/stagehand-java-core/build.gradle.kts @@ -27,8 +27,6 @@ dependencies { implementation("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2") implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2") implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.2") - implementation("org.apache.httpcomponents.core5:httpcore5:5.2.4") - implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") testImplementation(kotlin("test")) testImplementation(project(":stagehand-java-client-okhttp")) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt index 499197e..75a778b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/HttpRequestBodies.kt @@ -5,16 +5,16 @@ package com.browserbase.api.core.http import com.browserbase.api.core.MultipartField +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.databind.node.JsonNodeType +import java.io.ByteArrayInputStream import java.io.InputStream import java.io.OutputStream +import java.util.UUID import kotlin.jvm.optionals.getOrNull -import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder -import org.apache.hc.core5.http.ContentType -import org.apache.hc.core5.http.HttpEntity @JvmSynthetic internal inline fun json(jsonMapper: JsonMapper, value: T): HttpRequestBody = @@ -37,94 +37,231 @@ internal fun multipartFormData( jsonMapper: JsonMapper, fields: Map>, ): HttpRequestBody = - object : HttpRequestBody { - private val entity: HttpEntity by lazy { - MultipartEntityBuilder.create() - .apply { - fields.forEach { (name, field) -> - val knownValue = field.value.asKnown().getOrNull() - val parts = - if (knownValue is InputStream) { - // Read directly from the `InputStream` instead of reading it all - // into memory due to the `jsonMapper` serialization below. - sequenceOf(name to knownValue) - } else { - val node = jsonMapper.valueToTree(field.value) - serializePart(name, node) + MultipartBody.Builder() + .apply { + fields.forEach { (name, field) -> + val knownValue = field.value.asKnown().getOrNull() + val parts = + if (knownValue is InputStream) { + // Read directly from the `InputStream` instead of reading it all + // into memory due to the `jsonMapper` serialization below. + sequenceOf(name to knownValue) + } else { + val node = jsonMapper.valueToTree(field.value) + serializePart(name, node) + } + + parts.forEach { (name, bytes) -> + val partBody = + if (bytes is ByteArrayInputStream) { + val byteArray = bytes.readBytes() + + object : HttpRequestBody { + + override fun writeTo(outputStream: OutputStream) { + outputStream.write(byteArray) + } + + override fun contentType(): String = field.contentType + + override fun contentLength(): Long = byteArray.size.toLong() + + override fun repeatable(): Boolean = true + + override fun close() {} } + } else { + object : HttpRequestBody { + + override fun writeTo(outputStream: OutputStream) { + bytes.copyTo(outputStream) + } + + override fun contentType(): String = field.contentType + + override fun contentLength(): Long = -1L - parts.forEach { (name, bytes) -> - addBinaryBody( - name, - bytes, - ContentType.parseLenient(field.contentType), - field.filename().getOrNull(), - ) + override fun repeatable(): Boolean = false + + override fun close() = bytes.close() + } } - } + + addPart( + MultipartBody.Part.create( + name, + field.filename().getOrNull(), + field.contentType, + partBody, + ) + ) } - .build() + } } + .build() - private fun serializePart( - name: String, - node: JsonNode, - ): Sequence> = - when (node.nodeType) { - JsonNodeType.MISSING, - JsonNodeType.NULL -> emptySequence() - JsonNodeType.BINARY -> sequenceOf(name to node.binaryValue().inputStream()) - JsonNodeType.STRING -> sequenceOf(name to node.textValue().inputStream()) - JsonNodeType.BOOLEAN -> - sequenceOf(name to node.booleanValue().toString().inputStream()) - JsonNodeType.NUMBER -> - sequenceOf(name to node.numberValue().toString().inputStream()) - JsonNodeType.ARRAY -> - sequenceOf( - name to - node - .elements() - .asSequence() - .mapNotNull { element -> - when (element.nodeType) { - JsonNodeType.MISSING, - JsonNodeType.NULL -> null - JsonNodeType.STRING -> node.textValue() - JsonNodeType.BOOLEAN -> node.booleanValue().toString() - JsonNodeType.NUMBER -> node.numberValue().toString() - null, - JsonNodeType.BINARY, - JsonNodeType.ARRAY, - JsonNodeType.OBJECT, - JsonNodeType.POJO -> - throw StagehandInvalidDataException( - "Unexpected JsonNode type in array: ${node.nodeType}" - ) - } - } - .joinToString(",") - .inputStream() - ) - JsonNodeType.OBJECT -> - node.fields().asSequence().flatMap { (key, value) -> - serializePart("$name[$key]", value) - } - JsonNodeType.POJO, - null -> - throw StagehandInvalidDataException( - "Unexpected JsonNode type: ${node.nodeType}" - ) +private fun serializePart(name: String, node: JsonNode): Sequence> = + when (node.nodeType) { + JsonNodeType.MISSING, + JsonNodeType.NULL -> emptySequence() + JsonNodeType.BINARY -> sequenceOf(name to node.binaryValue().inputStream()) + JsonNodeType.STRING -> sequenceOf(name to node.textValue().byteInputStream()) + JsonNodeType.BOOLEAN -> sequenceOf(name to node.booleanValue().toString().byteInputStream()) + JsonNodeType.NUMBER -> sequenceOf(name to node.numberValue().toString().byteInputStream()) + JsonNodeType.ARRAY -> + sequenceOf( + name to + node + .elements() + .asSequence() + .mapNotNull { element -> + when (element.nodeType) { + JsonNodeType.MISSING, + JsonNodeType.NULL -> null + JsonNodeType.STRING -> element.textValue() + JsonNodeType.BOOLEAN -> element.booleanValue().toString() + JsonNodeType.NUMBER -> element.numberValue().toString() + null, + JsonNodeType.BINARY, + JsonNodeType.ARRAY, + JsonNodeType.OBJECT, + JsonNodeType.POJO -> + throw StagehandInvalidDataException( + "Unexpected JsonNode type in array: ${element.nodeType}" + ) + } + } + .joinToString(",") + .byteInputStream() + ) + JsonNodeType.OBJECT -> + node.fields().asSequence().flatMap { (key, value) -> + serializePart("$name[$key]", value) } + JsonNodeType.POJO, + null -> throw StagehandInvalidDataException("Unexpected JsonNode type: ${node.nodeType}") + } - private fun String.inputStream(): InputStream = toByteArray().inputStream() +private class MultipartBody +private constructor(private val boundary: String, private val parts: List) : HttpRequestBody { + private val boundaryBytes: ByteArray = boundary.toByteArray() + private val contentType = "multipart/form-data; boundary=$boundary" - override fun writeTo(outputStream: OutputStream) = entity.writeTo(outputStream) + // This must remain in sync with `contentLength`. + override fun writeTo(outputStream: OutputStream) { + parts.forEach { part -> + outputStream.write(DASHDASH) + outputStream.write(boundaryBytes) + outputStream.write(CRLF) - override fun contentType(): String = entity.contentType + outputStream.write(CONTENT_DISPOSITION) + outputStream.write(part.contentDisposition.toByteArray()) + outputStream.write(CRLF) - override fun contentLength(): Long = entity.contentLength + outputStream.write(CONTENT_TYPE) + outputStream.write(part.contentType.toByteArray()) + outputStream.write(CRLF) - override fun repeatable(): Boolean = entity.isRepeatable + outputStream.write(CRLF) + part.body.writeTo(outputStream) + outputStream.write(CRLF) + } - override fun close() = entity.close() + outputStream.write(DASHDASH) + outputStream.write(boundaryBytes) + outputStream.write(DASHDASH) + outputStream.write(CRLF) + } + + override fun contentType(): String = contentType + + // This must remain in sync with `writeTo`. + override fun contentLength(): Long { + var byteCount = 0L + + parts.forEach { part -> + val contentLength = part.body.contentLength() + if (contentLength == -1L) { + return -1L + } + + byteCount += + DASHDASH.size + + boundaryBytes.size + + CRLF.size + + CONTENT_DISPOSITION.size + + part.contentDisposition.toByteArray().size + + CRLF.size + + CONTENT_TYPE.size + + part.contentType.toByteArray().size + + CRLF.size + + CRLF.size + + contentLength + + CRLF.size + } + + byteCount += DASHDASH.size + boundaryBytes.size + DASHDASH.size + CRLF.size + return byteCount + } + + override fun repeatable(): Boolean = parts.all { it.body.repeatable() } + + override fun close() { + parts.forEach { it.body.close() } + } + + class Builder { + private val boundary = UUID.randomUUID().toString() + private val parts: MutableList = mutableListOf() + + fun addPart(part: Part) = apply { parts.add(part) } + + fun build() = MultipartBody(boundary, parts.toImmutable()) + } + + class Part + private constructor( + val contentDisposition: String, + val contentType: String, + val body: HttpRequestBody, + ) { + companion object { + fun create( + name: String, + filename: String?, + contentType: String, + body: HttpRequestBody, + ): Part { + val disposition = buildString { + append("form-data; name=") + appendQuotedString(name) + if (filename != null) { + append("; filename=") + appendQuotedString(filename) + } + } + return Part(disposition, contentType, body) + } + } + } + + companion object { + private val CRLF = byteArrayOf('\r'.code.toByte(), '\n'.code.toByte()) + private val DASHDASH = byteArrayOf('-'.code.toByte(), '-'.code.toByte()) + private val CONTENT_DISPOSITION = "Content-Disposition: ".toByteArray() + private val CONTENT_TYPE = "Content-Type: ".toByteArray() + + private fun StringBuilder.appendQuotedString(key: String) { + append('"') + for (ch in key) { + when (ch) { + '\n' -> append("%0A") + '\r' -> append("%0D") + '"' -> append("%22") + else -> append(ch) + } + } + append('"') + } } +} diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestBodiesTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestBodiesTest.kt new file mode 100644 index 0000000..2cf6fa4 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/HttpRequestBodiesTest.kt @@ -0,0 +1,729 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.core.http + +import com.browserbase.api.core.MultipartField +import com.browserbase.api.core.jsonMapper +import java.io.ByteArrayOutputStream +import java.io.InputStream +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class HttpRequestBodiesTest { + + @Test + fun multipartFormData_serializesFieldWithFilename() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "file" to + MultipartField.builder() + .value("hello") + .filename("hello.txt") + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(output.size().toLong()).isEqualTo(body.contentLength()) + val boundary = body.contentType()!!.substringAfter("multipart/form-data; boundary=") + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="file"; filename="hello.txt" + |Content-Type: text/plain + | + |hello + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesFieldWithoutFilename() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "field" to + MultipartField.builder() + .value("value") + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(output.size().toLong()).isEqualTo(body.contentLength()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="field" + |Content-Type: text/plain + | + |value + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesInputStream() { + // Use `.buffered()` to get a non-ByteArrayInputStream, which hits the non-repeatable code + // path. + val inputStream = "stream content".byteInputStream().buffered() + val body = + multipartFormData( + jsonMapper(), + mapOf( + "data" to + MultipartField.builder() + .value(inputStream) + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isFalse() + assertThat(body.contentLength()).isEqualTo(-1L) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="data" + |Content-Type: application/octet-stream + | + |stream content + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesByteArray() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "binary" to + MultipartField.builder() + .value("abc".toByteArray()) + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="binary" + |Content-Type: application/octet-stream + | + |abc + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesBooleanValue() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "flag" to + MultipartField.builder() + .value(true) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="flag" + |Content-Type: text/plain + | + |true + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesNumberValue() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "count" to + MultipartField.builder().value(42).contentType("text/plain").build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="count" + |Content-Type: text/plain + | + |42 + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesNullValueAsNoParts() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "present" to + MultipartField.builder() + .value("yes") + .contentType("text/plain") + .build(), + "absent" to + MultipartField.builder() + .value(null as String?) + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="present" + |Content-Type: text/plain + | + |yes + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesArray() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "items" to + MultipartField.builder>() + .value(listOf("alpha", "beta", "gamma")) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="items" + |Content-Type: text/plain + | + |alpha,beta,gamma + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesObjectAsNestedParts() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "meta" to + MultipartField.builder>() + .value(mapOf("key1" to "val1", "key2" to "val2")) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="meta[key1]" + |Content-Type: text/plain + | + |val1 + |--$boundary + |Content-Disposition: form-data; name="meta[key2]" + |Content-Type: text/plain + | + |val2 + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesMultipleFields() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "name" to + MultipartField.builder() + .value("Alice") + .contentType("text/plain") + .build(), + "age" to + MultipartField.builder().value(30).contentType("text/plain").build(), + "file" to + MultipartField.builder() + .value("file contents") + .filename("doc.txt") + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="name" + |Content-Type: text/plain + | + |Alice + |--$boundary + |Content-Disposition: form-data; name="age" + |Content-Type: text/plain + | + |30 + |--$boundary + |Content-Disposition: form-data; name="file"; filename="doc.txt" + |Content-Type: text/plain + | + |file contents + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_quotesSpecialCharactersInNameAndFilename() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "field\nname" to + MultipartField.builder() + .value("value") + .filename("file\r\"name.txt") + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="field%0Aname"; filename="file%0D%22name.txt" + |Content-Type: text/plain + | + |value + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_writeIsRepeatable() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "field" to + MultipartField.builder() + .value("repeatable") + .contentType("text/plain") + .build() + ), + ) + + val output1 = ByteArrayOutputStream() + body.writeTo(output1) + val output2 = ByteArrayOutputStream() + body.writeTo(output2) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output1.size().toLong()) + val boundary = boundary(body) + val expected = + """ + |--$boundary + |Content-Disposition: form-data; name="field" + |Content-Type: text/plain + | + |repeatable + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + assertThat(output1.toString("UTF-8")).isEqualTo(expected) + assertThat(output2.toString("UTF-8")).isEqualTo(expected) + } + + @Test + fun multipartFormData_serializesByteArrayInputStream() { + // ByteArrayInputStream is specifically handled as repeatable with known content length. + val inputStream = "byte array stream".byteInputStream() + val body = + multipartFormData( + jsonMapper(), + mapOf( + "data" to + MultipartField.builder() + .value(inputStream) + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="data" + |Content-Type: application/octet-stream + | + |byte array stream + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesInputStreamWithFilename() { + // Use `.buffered()` to get a non-ByteArrayInputStream, which hits the non-repeatable code + // path. + val inputStream = "file data".byteInputStream().buffered() + val body = + multipartFormData( + jsonMapper(), + mapOf( + "upload" to + MultipartField.builder() + .value(inputStream) + .filename("upload.bin") + .contentType("application/octet-stream") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isFalse() + assertThat(body.contentLength()).isEqualTo(-1L) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="upload"; filename="upload.bin" + |Content-Type: application/octet-stream + | + |file data + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesNestedArrayInObject() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "data" to + MultipartField.builder>>() + .value(mapOf("tags" to listOf("a", "b"))) + .contentType("text/plain") + .build() + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="data[tags]" + |Content-Type: text/plain + | + |a,b + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_contentLengthIsUnknownWhenInputStreamPresent() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "text" to + MultipartField.builder() + .value("hello") + .contentType("text/plain") + .build(), + "stream" to + MultipartField.builder() + // Use `.buffered()` to get a non-ByteArrayInputStream, which hits the + // non-repeatable code path. + .value("data".byteInputStream().buffered()) + .contentType("application/octet-stream") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isFalse() + assertThat(body.contentLength()).isEqualTo(-1L) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="text" + |Content-Type: text/plain + | + |hello + |--$boundary + |Content-Disposition: form-data; name="stream" + |Content-Type: application/octet-stream + | + |data + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesEmptyArray() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "required" to + MultipartField.builder() + .value("present") + .contentType("text/plain") + .build(), + "items" to + MultipartField.builder>() + .value(emptyList()) + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="required" + |Content-Type: text/plain + | + |present + |--$boundary + |Content-Disposition: form-data; name="items" + |Content-Type: text/plain + | + | + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + @Test + fun multipartFormData_serializesEmptyObject() { + val body = + multipartFormData( + jsonMapper(), + mapOf( + "required" to + MultipartField.builder() + .value("present") + .contentType("text/plain") + .build(), + "meta" to + MultipartField.builder>() + .value(emptyMap()) + .contentType("text/plain") + .build(), + ), + ) + + val output = ByteArrayOutputStream() + body.writeTo(output) + + assertThat(body.repeatable()).isTrue() + assertThat(body.contentLength()).isEqualTo(output.size().toLong()) + val boundary = boundary(body) + assertThat(output.toString("UTF-8")) + .isEqualTo( + """ + |--$boundary + |Content-Disposition: form-data; name="required" + |Content-Type: text/plain + | + |present + |--$boundary-- + | + """ + .trimMargin() + .replace("\n", "\r\n") + ) + } + + private fun boundary(body: HttpRequestBody): String = + body.contentType()!!.substringAfter("multipart/form-data; boundary=") +} From 4f189927f591ac853083070de8c628b054135abd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 06:21:43 +0000 Subject: [PATCH 114/164] fix: set Accept header in more places --- .../browserbase/api/services/async/SessionServiceAsyncImpl.kt | 4 ++++ .../browserbase/api/services/blocking/SessionServiceImpl.kt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt index 7652220..9a2fdc2 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/async/SessionServiceAsyncImpl.kt @@ -214,6 +214,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "act") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, @@ -327,6 +328,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "agentExecute") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, @@ -406,6 +408,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "extract") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, @@ -519,6 +522,7 @@ class SessionServiceAsyncImpl internal constructor(private val clientOptions: Cl .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "observe") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt index 35a7856..8367bf6 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/services/blocking/SessionServiceImpl.kt @@ -190,6 +190,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "act") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, @@ -294,6 +295,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "agentExecute") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, @@ -367,6 +369,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "extract") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, @@ -471,6 +474,7 @@ class SessionServiceImpl internal constructor(private val clientOptions: ClientO .method(HttpMethod.POST) .baseUrl(clientOptions.baseUrl()) .addPathSegments("v1", "sessions", params._pathParam(0), "observe") + .putHeader("Accept", "text/event-stream") .body( json( clientOptions.jsonMapper, From 637e72bfe31f1b5cbe980c545408c6326ec5ece4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:35:47 +0000 Subject: [PATCH 115/164] feat: [docsrevert spec gen changes --- .stats.yml | 4 ++-- buildSrc/src/main/kotlin/stagehand.publish.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index ea1fdd4..ba99884 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-6fd391f729eb05dc7b6168adff89e6198bc545ebd4ff737494d72288870e0977.yml -openapi_spec_hash: ee16862542659f47acc8dcd5669c7623 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-87b4d9e349de9d33d5d89439f7ac9507133700a9f072fdf0d756471961768d2c.yml +openapi_spec_hash: 0f6ae6d10a0227a3482914728cf901ba config_hash: 7386d24e2f03a3b2a89b3f6881446348 diff --git a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts index a24d7f5..50ca9dc 100644 --- a/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.publish.gradle.kts @@ -43,7 +43,7 @@ configure { pom { name.set("Stagehand API") - description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud.\n\n## Multi-Region Support\n\nThe Stagehand API is available in multiple regions. Choose the API endpoint that\nmatches where your browser session is running:\n\n| Region | Endpoint |\n| ------------------- | ------------------------------------------- |\n| us-west-2 (default) | https://api.stagehand.browserbase.com |\n| us-east-1 | https://api.use1.stagehand.browserbase.com |\n| eu-central-1 | https://api.euc1.stagehand.browserbase.com |\n| ap-southeast-1 | https://api.apse1.stagehand.browserbase.com |\n\n**Important:** The API endpoint must match your browser session region. If\nthere's a mismatch, you'll receive a BAD_REQUEST error:\n`Session is in region 'X' but this API instance serves 'Y'. Please route your request to the X Stagehand API endpoint.`\n\nTo disable API mode and use local browser automation, set `disableAPI: true` in\nyour Stagehand configuration.\n\n## Authentication and Usage\n\nAll endpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") + description.set("Stagehand SDK for AI browser automation [ALPHA]. This API allows clients to\nexecute browser automation tasks remotely on the Browserbase cloud. All\nendpoints except /sessions/start require an active session ID. Responses are\nstreamed using Server-Sent Events (SSE) when the `x-stream-response: true`\nheader is provided.\n\nThis SDK is currently ALPHA software and is not production ready! Please try it\nand give us your feedback, stay tuned for upcoming release announcements!") url.set("https://docs.stagehand.dev") licenses { From ba379157cfc0283c962261b30fdd32d614360180 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 05:44:10 +0000 Subject: [PATCH 116/164] chore(internal): expand imports --- .../browserbase/api/core/http/RetryingHttpClient.kt | 2 ++ .../api/core/http/RetryingHttpClientTest.kt | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt index 1305c6a..ab5bd0b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt @@ -1,3 +1,5 @@ +// File generated from our OpenAPI spec by Stainless. + package com.browserbase.api.core.http import com.browserbase.api.core.DefaultSleeper diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt index b3fbe9b..ce14c91 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt @@ -1,10 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. + package com.browserbase.api.core.http import com.browserbase.api.client.okhttp.OkHttpClient import com.browserbase.api.core.RequestOptions import com.browserbase.api.core.Sleeper import com.browserbase.api.errors.StagehandRetryableException -import com.github.tomakehurst.wiremock.client.WireMock.* +import com.github.tomakehurst.wiremock.client.WireMock.equalTo +import com.github.tomakehurst.wiremock.client.WireMock.matching +import com.github.tomakehurst.wiremock.client.WireMock.ok +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor +import com.github.tomakehurst.wiremock.client.WireMock.resetAllScenarios +import com.github.tomakehurst.wiremock.client.WireMock.serviceUnavailable +import com.github.tomakehurst.wiremock.client.WireMock.stubFor +import com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo +import com.github.tomakehurst.wiremock.client.WireMock.verify import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.github.tomakehurst.wiremock.stubbing.Scenario From a2f3291b599b193f6cdbc2fc10a94133c257c97c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 18:07:47 +0000 Subject: [PATCH 117/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index ba99884..98d7dd4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-87b4d9e349de9d33d5d89439f7ac9507133700a9f072fdf0d756471961768d2c.yml openapi_spec_hash: 0f6ae6d10a0227a3482914728cf901ba -config_hash: 7386d24e2f03a3b2a89b3f6881446348 +config_hash: 4252fc025e947bc0fd6b2abd91a0cc8e From a352b2f991e7b356dd2e64339dd8bd50653b7683 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 20:07:42 +0000 Subject: [PATCH 118/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 98d7dd4..ea8da3c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-87b4d9e349de9d33d5d89439f7ac9507133700a9f072fdf0d756471961768d2c.yml openapi_spec_hash: 0f6ae6d10a0227a3482914728cf901ba -config_hash: 4252fc025e947bc0fd6b2abd91a0cc8e +config_hash: 7baf2daccae5913216bb74c52d63eaff From 58d5a6dd9f5374a4fc59d6a8ab48ae985f49e73e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 23:04:18 +0000 Subject: [PATCH 119/164] feat: Add bedrock to provider enum in Zod schemas and OpenAPI spec --- .stats.yml | 6 +++--- .../com/browserbase/api/models/sessions/ModelConfig.kt | 6 ++++++ .../browserbase/api/models/sessions/SessionExecuteParams.kt | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index ea8da3c..c61740e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-87b4d9e349de9d33d5d89439f7ac9507133700a9f072fdf0d756471961768d2c.yml -openapi_spec_hash: 0f6ae6d10a0227a3482914728cf901ba -config_hash: 7baf2daccae5913216bb74c52d63eaff +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a4e672f457dd99336f4b2a113fd7c7c6c9db0941b38d57cff6e3641549a6c4ed.yml +openapi_spec_hash: eae9c8561e420db8e4d238c1e59617fb +config_hash: 2a565ad6662259a2e90fa5f1f5095525 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 49a3d65..1334949 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -283,6 +283,8 @@ private constructor( @JvmField val MICROSOFT = of("microsoft") + @JvmField val BEDROCK = of("bedrock") + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) } @@ -292,6 +294,7 @@ private constructor( ANTHROPIC, GOOGLE, MICROSOFT, + BEDROCK, } /** @@ -308,6 +311,7 @@ private constructor( ANTHROPIC, GOOGLE, MICROSOFT, + BEDROCK, /** An enum member indicating that [Provider] was instantiated with an unknown value. */ _UNKNOWN, } @@ -325,6 +329,7 @@ private constructor( ANTHROPIC -> Value.ANTHROPIC GOOGLE -> Value.GOOGLE MICROSOFT -> Value.MICROSOFT + BEDROCK -> Value.BEDROCK else -> Value._UNKNOWN } @@ -343,6 +348,7 @@ private constructor( ANTHROPIC -> Known.ANTHROPIC GOOGLE -> Known.GOOGLE MICROSOFT -> Known.MICROSOFT + BEDROCK -> Known.BEDROCK else -> throw StagehandInvalidDataException("Unknown Provider: $value") } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index b8a795f..65fd5a6 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -1522,6 +1522,8 @@ private constructor( @JvmField val MICROSOFT = of("microsoft") + @JvmField val BEDROCK = of("bedrock") + @JvmStatic fun of(value: String) = Provider(JsonField.of(value)) } @@ -1531,6 +1533,7 @@ private constructor( ANTHROPIC, GOOGLE, MICROSOFT, + BEDROCK, } /** @@ -1547,6 +1550,7 @@ private constructor( ANTHROPIC, GOOGLE, MICROSOFT, + BEDROCK, /** * An enum member indicating that [Provider] was instantiated with an unknown value. */ @@ -1566,6 +1570,7 @@ private constructor( ANTHROPIC -> Value.ANTHROPIC GOOGLE -> Value.GOOGLE MICROSOFT -> Value.MICROSOFT + BEDROCK -> Value.BEDROCK else -> Value._UNKNOWN } @@ -1584,6 +1589,7 @@ private constructor( ANTHROPIC -> Known.ANTHROPIC GOOGLE -> Known.GOOGLE MICROSOFT -> Known.MICROSOFT + BEDROCK -> Known.BEDROCK else -> throw StagehandInvalidDataException("Unknown Provider: $value") } From 2cd229a2d222d066b8d53a562449ab094e672bbd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 23:09:13 +0000 Subject: [PATCH 120/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ac03171..1b77f50 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.6.1" + ".": "0.7.0" } \ No newline at end of file diff --git a/README.md b/README.md index 7a37f08..2c23194 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.6.1) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.6.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.1) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.7.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.7.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.0) @@ -15,7 +15,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.6.1). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.0). @@ -26,7 +26,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.6.1") +implementation("com.browserbase.api:stagehand-java:0.7.0") ``` ### Maven @@ -35,7 +35,7 @@ implementation("com.browserbase.api:stagehand-java:0.6.1") com.browserbase.api stagehand-java - 0.6.1 + 0.7.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 49dfc3e..f240422 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.6.1" // x-release-please-version + version = "0.7.0" // x-release-please-version } subprojects { From 80eac76514a6b363a15e99e3a7e9dcdd439d7cf4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 22:20:21 +0000 Subject: [PATCH 121/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1b77f50..1bc5713 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.7.0" + ".": "0.7.1" } \ No newline at end of file diff --git a/README.md b/README.md index 2c23194..b560f82 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.7.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.7.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.7.1) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.7.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.1) @@ -15,7 +15,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.1). @@ -26,7 +26,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.7.0") +implementation("com.browserbase.api:stagehand-java:0.7.1") ``` ### Maven @@ -35,7 +35,7 @@ implementation("com.browserbase.api:stagehand-java:0.7.0") com.browserbase.api stagehand-java - 0.7.0 + 0.7.1 ``` diff --git a/build.gradle.kts b/build.gradle.kts index f240422..79fb854 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.7.0" // x-release-please-version + version = "0.7.1" // x-release-please-version } subprojects { From 8ebd3d9f7a10fc5167e93ffb48c686f1440c8496 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 08:40:33 +0000 Subject: [PATCH 122/164] chore(internal): codegen related update --- .../com/browserbase/api/core/http/RetryingHttpClient.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt index ab5bd0b..5ddfb06 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt @@ -214,13 +214,8 @@ private constructor( } } ?.let { retryAfterNanos -> - // If the API asks us to wait a certain amount of time (and it's a reasonable - // amount), just - // do what it says. - val retryAfter = Duration.ofNanos(retryAfterNanos.toLong()) - if (retryAfter in Duration.ofNanos(0)..Duration.ofMinutes(1)) { - return retryAfter - } + // If the API asks us to wait a certain amount of time, do what it says. + return Duration.ofNanos(retryAfterNanos.toLong()) } // Apply exponential backoff, but not more than the max. From 49c7501474d3746cb92dae8c3328ce0fc6fe207f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Mar 2026 08:43:37 +0000 Subject: [PATCH 123/164] chore(internal): bump palantir-java-format --- buildSrc/src/main/kotlin/stagehand.java.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts index 70fc33f..8f4f902 100644 --- a/buildSrc/src/main/kotlin/stagehand.java.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.java.gradle.kts @@ -45,7 +45,7 @@ tasks.withType().configureEach { val palantir by configurations.creating dependencies { - palantir("com.palantir.javaformat:palantir-java-format:2.73.0") + palantir("com.palantir.javaformat:palantir-java-format:2.89.0") } fun registerPalantir( From 5510ec5e36dcf482445bf81b298be94de6c0c06c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Mar 2026 17:36:58 +0000 Subject: [PATCH 124/164] chore(ci): skip uploading artifacts on stainless-internal branches --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27fda9e..5eb58fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,14 +65,18 @@ jobs: run: ./scripts/build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/stagehand-java' + if: |- + github.repository == 'stainless-sdks/stagehand-java' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Build and upload Maven artifacts - if: github.repository == 'stainless-sdks/stagehand-java' + if: |- + github.repository == 'stainless-sdks/stagehand-java' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} From 57dca2c5472002520577bd36ddda3e2eb9670fbf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 21:28:25 +0000 Subject: [PATCH 125/164] feat: Add missing cdpHeaders field to v3 server openapi spec --- .stats.yml | 4 +- .../api/models/sessions/SessionStartParams.kt | 147 ++++++++++++++++- .../models/sessions/SessionStartParamsTest.kt | 20 +++ .../api/services/ErrorHandlingTest.kt | 153 ++++++++++++++++++ .../api/services/ServiceParamsTest.kt | 5 + .../services/async/SessionServiceAsyncTest.kt | 6 + .../services/blocking/SessionServiceTest.kt | 6 + 7 files changed, 338 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index c61740e..a959f06 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a4e672f457dd99336f4b2a113fd7c7c6c9db0941b38d57cff6e3641549a6c4ed.yml -openapi_spec_hash: eae9c8561e420db8e4d238c1e59617fb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-573d364768ac1902ee5ed8b2485d3b293bda0ea8ff7898aef1a3fd6be79b594a.yml +openapi_spec_hash: 107ec840f4330885dd2232a05a66fed7 config_hash: 2a565ad6662259a2e90fa5f1f5095525 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index f177a4e..5e09071 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -1372,6 +1372,7 @@ private constructor( private constructor( private val acceptDownloads: JsonField, private val args: JsonField>, + private val cdpHeaders: JsonField, private val cdpUrl: JsonField, private val chromiumSandbox: JsonField, private val connectTimeoutMs: JsonField, @@ -1400,6 +1401,9 @@ private constructor( @JsonProperty("args") @ExcludeMissing args: JsonField> = JsonMissing.of(), + @JsonProperty("cdpHeaders") + @ExcludeMissing + cdpHeaders: JsonField = JsonMissing.of(), @JsonProperty("cdpUrl") @ExcludeMissing cdpUrl: JsonField = JsonMissing.of(), @@ -1450,6 +1454,7 @@ private constructor( ) : this( acceptDownloads, args, + cdpHeaders, cdpUrl, chromiumSandbox, connectTimeoutMs, @@ -1483,6 +1488,12 @@ private constructor( */ fun args(): Optional> = args.getOptional("args") + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun cdpHeaders(): Optional = cdpHeaders.getOptional("cdpHeaders") + /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. * if the server responded with an unexpected value). @@ -1608,6 +1619,16 @@ private constructor( */ @JsonProperty("args") @ExcludeMissing fun _args(): JsonField> = args + /** + * Returns the raw JSON value of [cdpHeaders]. + * + * Unlike [cdpHeaders], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("cdpHeaders") + @ExcludeMissing + fun _cdpHeaders(): JsonField = cdpHeaders + /** * Returns the raw JSON value of [cdpUrl]. * @@ -1783,6 +1804,7 @@ private constructor( private var acceptDownloads: JsonField = JsonMissing.of() private var args: JsonField>? = null + private var cdpHeaders: JsonField = JsonMissing.of() private var cdpUrl: JsonField = JsonMissing.of() private var chromiumSandbox: JsonField = JsonMissing.of() private var connectTimeoutMs: JsonField = JsonMissing.of() @@ -1806,6 +1828,7 @@ private constructor( internal fun from(launchOptions: LaunchOptions) = apply { acceptDownloads = launchOptions.acceptDownloads args = launchOptions.args.map { it.toMutableList() } + cdpHeaders = launchOptions.cdpHeaders cdpUrl = launchOptions.cdpUrl chromiumSandbox = launchOptions.chromiumSandbox connectTimeoutMs = launchOptions.connectTimeoutMs @@ -1865,6 +1888,19 @@ private constructor( } } + fun cdpHeaders(cdpHeaders: CdpHeaders) = cdpHeaders(JsonField.of(cdpHeaders)) + + /** + * Sets [Builder.cdpHeaders] to an arbitrary JSON value. + * + * You should usually call [Builder.cdpHeaders] with a well-typed [CdpHeaders] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun cdpHeaders(cdpHeaders: JsonField) = apply { + this.cdpHeaders = cdpHeaders + } + fun cdpUrl(cdpUrl: String) = cdpUrl(JsonField.of(cdpUrl)) /** @@ -2120,6 +2156,7 @@ private constructor( LaunchOptions( acceptDownloads, (args ?: JsonMissing.of()).map { it.toImmutable() }, + cdpHeaders, cdpUrl, chromiumSandbox, connectTimeoutMs, @@ -2150,6 +2187,7 @@ private constructor( acceptDownloads() args() + cdpHeaders().ifPresent { it.validate() } cdpUrl() chromiumSandbox() connectTimeoutMs() @@ -2188,6 +2226,7 @@ private constructor( internal fun validity(): Int = (if (acceptDownloads.asKnown().isPresent) 1 else 0) + (args.asKnown().getOrNull()?.size ?: 0) + + (cdpHeaders.asKnown().getOrNull()?.validity() ?: 0) + (if (cdpUrl.asKnown().isPresent) 1 else 0) + (if (chromiumSandbox.asKnown().isPresent) 1 else 0) + (if (connectTimeoutMs.asKnown().isPresent) 1 else 0) + @@ -2206,6 +2245,110 @@ private constructor( (if (userDataDir.asKnown().isPresent) 1 else 0) + (viewport.asKnown().getOrNull()?.validity() ?: 0) + class CdpHeaders + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [CdpHeaders]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [CdpHeaders]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(cdpHeaders: CdpHeaders) = apply { + additionalProperties = cdpHeaders.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [CdpHeaders]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): CdpHeaders = CdpHeaders(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): CdpHeaders = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CdpHeaders && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "CdpHeaders{additionalProperties=$additionalProperties}" + } + @JsonDeserialize(using = IgnoreDefaultArgs.Deserializer::class) @JsonSerialize(using = IgnoreDefaultArgs.Serializer::class) class IgnoreDefaultArgs @@ -2872,6 +3015,7 @@ private constructor( return other is LaunchOptions && acceptDownloads == other.acceptDownloads && args == other.args && + cdpHeaders == other.cdpHeaders && cdpUrl == other.cdpUrl && chromiumSandbox == other.chromiumSandbox && connectTimeoutMs == other.connectTimeoutMs && @@ -2896,6 +3040,7 @@ private constructor( Objects.hash( acceptDownloads, args, + cdpHeaders, cdpUrl, chromiumSandbox, connectTimeoutMs, @@ -2920,7 +3065,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, port=$port, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}" + "LaunchOptions{acceptDownloads=$acceptDownloads, args=$args, cdpHeaders=$cdpHeaders, cdpUrl=$cdpUrl, chromiumSandbox=$chromiumSandbox, connectTimeoutMs=$connectTimeoutMs, deviceScaleFactor=$deviceScaleFactor, devtools=$devtools, downloadsPath=$downloadsPath, executablePath=$executablePath, hasTouch=$hasTouch, headless=$headless, ignoreDefaultArgs=$ignoreDefaultArgs, ignoreHttpsErrors=$ignoreHttpsErrors, locale=$locale, port=$port, preserveUserDataDir=$preserveUserDataDir, proxy=$proxy, userDataDir=$userDataDir, viewport=$viewport, additionalProperties=$additionalProperties}" } /** Browser type to use */ diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index e22e941..5b35aaa 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -22,6 +22,11 @@ internal class SessionStartParamsTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -168,6 +173,11 @@ internal class SessionStartParamsTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -331,6 +341,11 @@ internal class SessionStartParamsTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -478,6 +493,11 @@ internal class SessionStartParamsTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index a28b993..a123b5c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -84,6 +84,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -261,6 +270,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -438,6 +456,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -615,6 +642,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -792,6 +828,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -969,6 +1014,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -1146,6 +1200,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -1323,6 +1386,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -1500,6 +1572,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -1677,6 +1758,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -1854,6 +1944,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -2031,6 +2130,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -2208,6 +2316,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -2385,6 +2502,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -2562,6 +2688,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -2739,6 +2874,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) @@ -2914,6 +3058,15 @@ internal class ErrorHandlingTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty( + "foo", + JsonValue.from("string"), + ) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index f3a40b7..33f3131 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -58,6 +58,11 @@ internal class ServiceParamsTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 2a0e601..ce43fba 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -493,6 +493,12 @@ internal class SessionServiceAsyncTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index dedab31..3392149 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -486,6 +486,12 @@ internal class SessionServiceTest { SessionStartParams.Browser.LaunchOptions.builder() .acceptDownloads(true) .addArg("string") + .cdpHeaders( + SessionStartParams.Browser.LaunchOptions.CdpHeaders + .builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .cdpUrl("cdpUrl") .chromiumSandbox(true) .connectTimeoutMs(0.0) From 9e0c6aaefca5a638032a61901141f34d2571947a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 00:33:28 +0000 Subject: [PATCH 126/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index a959f06..cefb031 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-573d364768ac1902ee5ed8b2485d3b293bda0ea8ff7898aef1a3fd6be79b594a.yml openapi_spec_hash: 107ec840f4330885dd2232a05a66fed7 -config_hash: 2a565ad6662259a2e90fa5f1f5095525 +config_hash: 0209737a4ab2a71afececb0ff7459998 From 88f71016462dd746aac9c7d6cd1ce8092a343e53 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 08:23:01 +0000 Subject: [PATCH 127/164] fix(client): incorrect `Retry-After` parsing --- .../api/core/http/RetryingHttpClient.kt | 2 +- .../api/core/http/RetryingHttpClientTest.kt | 224 +++++++++++++++--- 2 files changed, 192 insertions(+), 34 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt index 5ddfb06..381b36f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/RetryingHttpClient.kt @@ -201,7 +201,7 @@ private constructor( ?: headers.values("Retry-After").getOrNull(0)?.let { retryAfter -> retryAfter.toFloatOrNull()?.times(TimeUnit.SECONDS.toNanos(1)) ?: try { - ChronoUnit.MILLIS.between( + ChronoUnit.NANOS.between( OffsetDateTime.now(clock), OffsetDateTime.parse( retryAfter, diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt index ce14c91..46d5ade 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt @@ -20,7 +20,11 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.github.tomakehurst.wiremock.stubbing.Scenario import java.io.InputStream +import java.time.Clock import java.time.Duration +import java.time.OffsetDateTime +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter import java.util.concurrent.CompletableFuture import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach @@ -36,6 +40,21 @@ internal class RetryingHttpClientTest { private lateinit var baseUrl: String private lateinit var httpClient: HttpClient + private class RecordingSleeper : Sleeper { + val durations = mutableListOf() + + override fun sleep(duration: Duration) { + durations.add(duration) + } + + override fun sleepAsync(duration: Duration): CompletableFuture { + durations.add(duration) + return CompletableFuture.completedFuture(null) + } + + override fun close() {} + } + @BeforeEach fun beforeEach(wmRuntimeInfo: WireMockRuntimeInfo) { baseUrl = wmRuntimeInfo.httpBaseUrl @@ -86,7 +105,8 @@ internal class RetryingHttpClientTest { @ValueSource(booleans = [false, true]) fun execute(async: Boolean) { stubFor(post(urlPathEqualTo("/something")).willReturn(ok())) - val retryingClient = retryingHttpClientBuilder().build() + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).build() val response = retryingClient.execute( @@ -100,6 +120,7 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(200) verify(1, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).isEmpty() assertNoResponseLeaks() } @@ -111,8 +132,12 @@ internal class RetryingHttpClientTest { .withHeader("X-Some-Header", matching("stainless-java-retry-.+")) .willReturn(ok()) ) + val sleeper = RecordingSleeper() val retryingClient = - retryingHttpClientBuilder().maxRetries(2).idempotencyHeader("X-Some-Header").build() + retryingHttpClientBuilder(sleeper) + .maxRetries(2) + .idempotencyHeader("X-Some-Header") + .build() val response = retryingClient.execute( @@ -126,20 +151,20 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(200) verify(1, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).isEmpty() assertNoResponseLeaks() } @ParameterizedTest @ValueSource(booleans = [false, true]) fun execute_withRetryAfterHeader(async: Boolean) { + val retryAfterDate = "Wed, 21 Oct 2015 07:28:00 GMT" stubFor( post(urlPathEqualTo("/something")) // First we fail with a retry after header given as a date .inScenario("foo") .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT") - ) + .willReturn(serviceUnavailable().withHeader("Retry-After", retryAfterDate)) .willSetStateTo("RETRY_AFTER_DATE") ) stubFor( @@ -158,7 +183,13 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() + // Fix the clock to 5 seconds before the Retry-After date so the date-based backoff is + // deterministic. + val retryAfterDateTime = + OffsetDateTime.parse(retryAfterDate, DateTimeFormatter.RFC_1123_DATE_TIME) + val clock = Clock.fixed(retryAfterDateTime.minusSeconds(5).toInstant(), ZoneOffset.UTC) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper, clock).maxRetries(2).build() val response = retryingClient.execute( @@ -186,19 +217,20 @@ internal class RetryingHttpClientTest { postRequestedFor(urlPathEqualTo("/something")) .withHeader("x-stainless-retry-count", equalTo("2")), ) + assertThat(sleeper.durations) + .containsExactly(Duration.ofSeconds(5), Duration.ofMillis(1234)) assertNoResponseLeaks() } @ParameterizedTest @ValueSource(booleans = [false, true]) fun execute_withOverwrittenRetryCountHeader(async: Boolean) { + val retryAfterDate = "Wed, 21 Oct 2015 07:28:00 GMT" stubFor( post(urlPathEqualTo("/something")) .inScenario("foo") // first we fail with a retry after header given as a date .whenScenarioStateIs(Scenario.STARTED) - .willReturn( - serviceUnavailable().withHeader("Retry-After", "Wed, 21 Oct 2015 07:28:00 GMT") - ) + .willReturn(serviceUnavailable().withHeader("Retry-After", retryAfterDate)) .willSetStateTo("RETRY_AFTER_DATE") ) stubFor( @@ -208,7 +240,11 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = retryingHttpClientBuilder().maxRetries(2).build() + val retryAfterDateTime = + OffsetDateTime.parse(retryAfterDate, DateTimeFormatter.RFC_1123_DATE_TIME) + val clock = Clock.fixed(retryAfterDateTime.minusSeconds(5).toInstant(), ZoneOffset.UTC) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper, clock).maxRetries(2).build() val response = retryingClient.execute( @@ -227,6 +263,7 @@ internal class RetryingHttpClientTest { postRequestedFor(urlPathEqualTo("/something")) .withHeader("x-stainless-retry-count", equalTo("42")), ) + assertThat(sleeper.durations).containsExactly(Duration.ofSeconds(5)) assertNoResponseLeaks() } @@ -247,7 +284,8 @@ internal class RetryingHttpClientTest { .willReturn(ok()) .willSetStateTo("COMPLETED") ) - val retryingClient = retryingHttpClientBuilder().maxRetries(1).build() + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(1).build() val response = retryingClient.execute( @@ -261,6 +299,7 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(200) verify(2, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).containsExactly(Duration.ofMillis(10)) assertNoResponseLeaks() } @@ -301,21 +340,12 @@ internal class RetryingHttpClientTest { override fun close() = httpClient.close() } + val sleeper = RecordingSleeper() val retryingClient = RetryingHttpClient.builder() .httpClient(failingHttpClient) .maxRetries(2) - .sleeper( - object : Sleeper { - - override fun sleep(duration: Duration) {} - - override fun sleepAsync(duration: Duration): CompletableFuture = - CompletableFuture.completedFuture(null) - - override fun close() {} - } - ) + .sleeper(sleeper) .build() val response = @@ -339,25 +369,153 @@ internal class RetryingHttpClientTest { postRequestedFor(urlPathEqualTo("/something")) .withHeader("x-stainless-retry-count", equalTo("0")), ) + // Exponential backoff with jitter: 0.5s * jitter where jitter is in [0.75, 1.0]. + assertThat(sleeper.durations).hasSize(1) + assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) assertNoResponseLeaks() } - private fun retryingHttpClientBuilder() = - RetryingHttpClient.builder() - .httpClient(httpClient) - // Use a no-op `Sleeper` to make the test fast. - .sleeper( - object : Sleeper { + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withExponentialBackoff(async: Boolean) { + stubFor(post(urlPathEqualTo("/something")).willReturn(serviceUnavailable())) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(3).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) - override fun sleep(duration: Duration) {} + // All retries exhausted; the last 503 response is returned. + assertThat(response.statusCode()).isEqualTo(503) + verify(4, postRequestedFor(urlPathEqualTo("/something"))) + // Exponential backoff with jitter: backoff = min(0.5 * 2^(retries-1), 8) * jitter where + // jitter is in [0.75, 1.0]. + assertThat(sleeper.durations).hasSize(3) + // retries=1: 0.5s * [0.75, 1.0] + assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) + // retries=2: 1.0s * [0.75, 1.0] + assertThat(sleeper.durations[1]).isBetween(Duration.ofMillis(750), Duration.ofMillis(1000)) + // retries=3: 2.0s * [0.75, 1.0] + assertThat(sleeper.durations[2]).isBetween(Duration.ofMillis(1500), Duration.ofMillis(2000)) + assertNoResponseLeaks() + } - override fun sleepAsync(duration: Duration): CompletableFuture = - CompletableFuture.completedFuture(null) + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withExponentialBackoffCap(async: Boolean) { + stubFor(post(urlPathEqualTo("/something")).willReturn(serviceUnavailable())) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(6).build() - override fun close() {} - } + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, ) + assertThat(response.statusCode()).isEqualTo(503) + verify(7, postRequestedFor(urlPathEqualTo("/something"))) + assertThat(sleeper.durations).hasSize(6) + // retries=5: min(0.5 * 2^4, 8) = 8.0s * [0.75, 1.0] + assertThat(sleeper.durations[4]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) + // retries=6: min(0.5 * 2^5, 8) = min(16, 8) = 8.0s * [0.75, 1.0] (capped) + assertThat(sleeper.durations[5]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterMsPriorityOverRetryAfter(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + serviceUnavailable() + .withHeader("Retry-After-Ms", "50") + .withHeader("Retry-After", "2") + ) + .willSetStateTo("RETRY") + ) + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs("RETRY") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(1).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + // Retry-After-Ms (50ms) takes priority over Retry-After (2s). + assertThat(sleeper.durations).containsExactly(Duration.ofMillis(50)) + assertNoResponseLeaks() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun execute_withRetryAfterUnparseable(async: Boolean) { + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn(serviceUnavailable().withHeader("Retry-After", "not-a-date-or-number")) + .willSetStateTo("RETRY") + ) + stubFor( + post(urlPathEqualTo("/something")) + .inScenario("foo") + .whenScenarioStateIs("RETRY") + .willReturn(ok()) + .willSetStateTo("COMPLETED") + ) + val sleeper = RecordingSleeper() + val retryingClient = retryingHttpClientBuilder(sleeper).maxRetries(1).build() + + val response = + retryingClient.execute( + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl(baseUrl) + .addPathSegment("something") + .build(), + async, + ) + + assertThat(response.statusCode()).isEqualTo(200) + // Unparseable Retry-After falls through to exponential backoff. + assertThat(sleeper.durations).hasSize(1) + assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) + assertNoResponseLeaks() + } + + private fun retryingHttpClientBuilder( + sleeper: RecordingSleeper, + clock: Clock = Clock.systemUTC(), + ) = RetryingHttpClient.builder().httpClient(httpClient).sleeper(sleeper).clock(clock) + private fun HttpClient.execute(request: HttpRequest, async: Boolean): HttpResponse = if (async) executeAsync(request).get() else execute(request) From 7004d53df346be7d2310ef253d3f870c970fd3bf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 11:15:18 +0000 Subject: [PATCH 128/164] chore(internal): tweak CI branches --- .github/workflows/ci.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5eb58fb..6a2d45c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' From aa55c415a5a7a350441d129a7f26b91350cc7d5f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2026 10:10:03 +0000 Subject: [PATCH 129/164] chore(internal): update retry delay tests --- .../browserbase/api/core/http/RetryingHttpClientTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt index 46d5ade..49e0138 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/RetryingHttpClientTest.kt @@ -400,9 +400,9 @@ internal class RetryingHttpClientTest { assertThat(sleeper.durations).hasSize(3) // retries=1: 0.5s * [0.75, 1.0] assertThat(sleeper.durations[0]).isBetween(Duration.ofMillis(375), Duration.ofMillis(500)) - // retries=2: 1.0s * [0.75, 1.0] + // retries=2: 1s * [0.75, 1.0] assertThat(sleeper.durations[1]).isBetween(Duration.ofMillis(750), Duration.ofMillis(1000)) - // retries=3: 2.0s * [0.75, 1.0] + // retries=3: 2s * [0.75, 1.0] assertThat(sleeper.durations[2]).isBetween(Duration.ofMillis(1500), Duration.ofMillis(2000)) assertNoResponseLeaks() } @@ -427,9 +427,9 @@ internal class RetryingHttpClientTest { assertThat(response.statusCode()).isEqualTo(503) verify(7, postRequestedFor(urlPathEqualTo("/something"))) assertThat(sleeper.durations).hasSize(6) - // retries=5: min(0.5 * 2^4, 8) = 8.0s * [0.75, 1.0] + // retries=5: backoff hits the 8s cap * [0.75, 1.0] assertThat(sleeper.durations[4]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) - // retries=6: min(0.5 * 2^5, 8) = min(16, 8) = 8.0s * [0.75, 1.0] (capped) + // retries=6: still capped at 8s * [0.75, 1.0] assertThat(sleeper.durations[5]).isBetween(Duration.ofMillis(6000), Duration.ofMillis(8000)) assertNoResponseLeaks() } From d934e6cbab8910ccd7d8b92828632607e32a191a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2026 10:28:38 +0000 Subject: [PATCH 130/164] fix(client): allow updating header/query affecting fields in `toBuilder()` --- .../com/browserbase/api/core/ClientOptions.kt | 11 ++++--- .../browserbase/api/core/ClientOptionsTest.kt | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 8b1c7f0..ac6a5ef 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -485,23 +485,24 @@ private constructor( headers.put("X-Stainless-Runtime", "JRE") headers.put("X-Stainless-Runtime-Version", getJavaVersion()) headers.put("X-Stainless-Kotlin-Version", KotlinVersion.CURRENT.toString()) + // We replace after all the default headers to allow end-users to overwrite them. + headers.replaceAll(this.headers.build()) + queryParams.replaceAll(this.queryParams.build()) browserbaseApiKey.let { if (!it.isEmpty()) { - headers.put("x-bb-api-key", it) + headers.replace("x-bb-api-key", it) } } browserbaseProjectId.let { if (!it.isEmpty()) { - headers.put("x-bb-project-id", it) + headers.replace("x-bb-project-id", it) } } modelApiKey.let { if (!it.isEmpty()) { - headers.put("x-model-api-key", it) + headers.replace("x-model-api-key", it) } } - headers.replaceAll(this.headers.build()) - queryParams.replaceAll(this.queryParams.build()) return ClientOptions( httpClient, diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt index 75d56e8..1bd88a6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/ClientOptionsTest.kt @@ -16,6 +16,37 @@ internal class ClientOptionsTest { private val httpClient = mock() + @Test + fun putHeader_canOverwriteDefaultHeader() { + val clientOptions = + ClientOptions.builder() + .httpClient(httpClient) + .putHeader("User-Agent", "My User Agent") + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + + assertThat(clientOptions.headers.values("User-Agent")).containsExactly("My User Agent") + } + + @Test + fun toBuilder_bbApiKeyAuthCanBeUpdated() { + var clientOptions = + ClientOptions.builder() + .httpClient(httpClient) + .browserbaseApiKey("My Browserbase API Key") + .browserbaseProjectId("My Browserbase Project ID") + .modelApiKey("My Model API Key") + .build() + + clientOptions = + clientOptions.toBuilder().browserbaseApiKey("another My Browserbase API Key").build() + + assertThat(clientOptions.headers.values("x-bb-api-key")) + .containsExactly("another My Browserbase API Key") + } + @Test fun toBuilder_whenOriginalClientOptionsGarbageCollected_doesNotCloseOriginalClient() { var clientOptions = From ae187189a0b3aacf3657eb918c76fc33695caf0a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:26:35 +0000 Subject: [PATCH 131/164] feat: [STG-1607] Yield finished SSE event instead of silently dropping it --- .stats.yml | 2 +- .../com/browserbase/api/core/handlers/SseHandler.kt | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/.stats.yml b/.stats.yml index cefb031..ead4868 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-573d364768ac1902ee5ed8b2485d3b293bda0ea8ff7898aef1a3fd6be79b594a.yml openapi_spec_hash: 107ec840f4330885dd2232a05a66fed7 -config_hash: 0209737a4ab2a71afececb0ff7459998 +config_hash: ab1c1122e862f9bdb6db4df36d489701 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt index f8e870e..359db63 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -18,22 +18,11 @@ import com.fasterxml.jackson.module.kotlin.jacksonTypeRef internal fun sseHandler(jsonMapper: JsonMapper): Handler> = streamHandler { response, lines -> val state = SseState(jsonMapper) - var done = false for (line in lines) { - // Stop emitting messages, but iterate through the full stream. - if (done) { - continue - } - val message = state.decode(line) ?: continue when { - message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> { - // In this case we don't break because we still want to iterate through the full - // stream. - done = true - continue - } + message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> yield(message) message.data.startsWith("error") -> { throw SseException.builder() .statusCode(response.statusCode()) From 1e3771f53eef5a9a347b26bdb8c4130e8619681a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 18:31:26 +0000 Subject: [PATCH 132/164] feat: Revert broken finished SSE yield config --- .stats.yml | 2 +- .../com/browserbase/api/core/handlers/SseHandler.kt | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ead4868..cefb031 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-573d364768ac1902ee5ed8b2485d3b293bda0ea8ff7898aef1a3fd6be79b594a.yml openapi_spec_hash: 107ec840f4330885dd2232a05a66fed7 -config_hash: ab1c1122e862f9bdb6db4df36d489701 +config_hash: 0209737a4ab2a71afececb0ff7459998 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt index 359db63..f8e870e 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -18,11 +18,22 @@ import com.fasterxml.jackson.module.kotlin.jacksonTypeRef internal fun sseHandler(jsonMapper: JsonMapper): Handler> = streamHandler { response, lines -> val state = SseState(jsonMapper) + var done = false for (line in lines) { + // Stop emitting messages, but iterate through the full stream. + if (done) { + continue + } + val message = state.decode(line) ?: continue when { - message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> yield(message) + message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> { + // In this case we don't break because we still want to iterate through the full + // stream. + done = true + continue + } message.data.startsWith("error") -> { throw SseException.builder() .statusCode(response.statusCode()) From a0f276402827606e026baa84ddb860b70f6c7ed5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 03:32:10 +0000 Subject: [PATCH 133/164] chore(internal): bump ktfmt --- buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts | 2 +- scripts/fast-format | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts index be6cf65..2e59660 100644 --- a/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/stagehand.kotlin.gradle.kts @@ -40,7 +40,7 @@ tasks.withType().configureEach { val ktfmt by configurations.creating dependencies { - ktfmt("com.facebook:ktfmt:0.56") + ktfmt("com.facebook:ktfmt:0.61") } fun registerKtfmt( diff --git a/scripts/fast-format b/scripts/fast-format index 1b3bc47..35a1dee 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -24,8 +24,8 @@ if [ ! -f "$FILE_LIST" ]; then exit 1 fi -if ! command -v ktfmt-fast-format &> /dev/null; then - echo "Error: ktfmt-fast-format not found" +if ! command -v ktfmt &> /dev/null; then + echo "Error: ktfmt not found" exit 1 fi @@ -36,7 +36,7 @@ echo "==> Done looking for Kotlin files" if [[ -n "$kt_files" ]]; then echo "==> will format Kotlin files" - echo "$kt_files" | tr '\n' '\0' | xargs -0 ktfmt-fast-format --kotlinlang-style "$@" + echo "$kt_files" | tr '\n' '\0' | xargs -0 ktfmt --kotlinlang-style "$@" else echo "No Kotlin files to format -- expected outcome during incremental formatting" fi From 50cb9985abfc0dadcf8140baed73c56cae1d4be7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 23 Mar 2026 19:10:33 +0000 Subject: [PATCH 134/164] feat: variables for observe --- .stats.yml | 4 +- .../api/models/sessions/SessionActParams.kt | 13 +- .../models/sessions/SessionExecuteParams.kt | 97 ++++++++++- .../models/sessions/SessionObserveParams.kt | 162 +++++++++++++++++- .../models/sessions/SessionActParamsTest.kt | 36 ++++ .../sessions/SessionExecuteParamsTest.kt | 8 + .../sessions/SessionObserveParamsTest.kt | 57 ++++++ .../api/services/ServiceParamsTest.kt | 9 + .../services/async/SessionServiceAsyncTest.kt | 50 ++++++ .../services/blocking/SessionServiceTest.kt | 50 ++++++ 10 files changed, 471 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index cefb031..4f6d212 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-573d364768ac1902ee5ed8b2485d3b293bda0ea8ff7898aef1a3fd6be79b594a.yml -openapi_spec_hash: 107ec840f4330885dd2232a05a66fed7 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-975ca868b31b1e45fb00b31a53d9df1ceec8663f6c2851bf40fdaa84171afadc.yml +openapi_spec_hash: 37891379e0f47e5c69769fbaa1064dab config_hash: 0209737a4ab2a71afececb0ff7459998 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 3445d78..6d92b39 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -805,7 +805,8 @@ private constructor( fun timeout(): Optional = timeout.getOptional("timeout") /** - * Variables to substitute in the action instruction + * Variables to substitute in the action instruction. Accepts flat primitives or { value, + * description? } objects. * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -899,7 +900,10 @@ private constructor( */ fun timeout(timeout: JsonField) = apply { this.timeout = timeout } - /** Variables to substitute in the action instruction */ + /** + * Variables to substitute in the action instruction. Accepts flat primitives or { + * value, description? } objects. + */ fun variables(variables: Variables) = variables(JsonField.of(variables)) /** @@ -1144,7 +1148,10 @@ private constructor( } } - /** Variables to substitute in the action instruction */ + /** + * Variables to substitute in the action instruction. Accepts flat primitives or { value, + * description? } objects. + */ class Variables @JsonCreator private constructor( diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 65fd5a6..f68232a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -1686,6 +1686,8 @@ private constructor( private val instruction: JsonField, private val highlightCursor: JsonField, private val maxSteps: JsonField, + private val toolTimeout: JsonField, + private val useSearch: JsonField, private val additionalProperties: MutableMap, ) { @@ -1697,8 +1699,16 @@ private constructor( @JsonProperty("highlightCursor") @ExcludeMissing highlightCursor: JsonField = JsonMissing.of(), - @JsonProperty("maxSteps") @ExcludeMissing maxSteps: JsonField = JsonMissing.of(), - ) : this(instruction, highlightCursor, maxSteps, mutableMapOf()) + @JsonProperty("maxSteps") + @ExcludeMissing + maxSteps: JsonField = JsonMissing.of(), + @JsonProperty("toolTimeout") + @ExcludeMissing + toolTimeout: JsonField = JsonMissing.of(), + @JsonProperty("useSearch") + @ExcludeMissing + useSearch: JsonField = JsonMissing.of(), + ) : this(instruction, highlightCursor, maxSteps, toolTimeout, useSearch, mutableMapOf()) /** * Natural language instruction for the agent @@ -1724,6 +1734,22 @@ private constructor( */ fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") + /** + * Timeout in milliseconds for each agent tool call + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun toolTimeout(): Optional = toolTimeout.getOptional("toolTimeout") + + /** + * Whether to enable the web search tool powered by Browserbase Search API + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun useSearch(): Optional = useSearch.getOptional("useSearch") + /** * Returns the raw JSON value of [instruction]. * @@ -1750,6 +1776,22 @@ private constructor( */ @JsonProperty("maxSteps") @ExcludeMissing fun _maxSteps(): JsonField = maxSteps + /** + * Returns the raw JSON value of [toolTimeout]. + * + * Unlike [toolTimeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("toolTimeout") + @ExcludeMissing + fun _toolTimeout(): JsonField = toolTimeout + + /** + * Returns the raw JSON value of [useSearch]. + * + * Unlike [useSearch], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("useSearch") @ExcludeMissing fun _useSearch(): JsonField = useSearch + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1781,6 +1823,8 @@ private constructor( private var instruction: JsonField? = null private var highlightCursor: JsonField = JsonMissing.of() private var maxSteps: JsonField = JsonMissing.of() + private var toolTimeout: JsonField = JsonMissing.of() + private var useSearch: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -1788,6 +1832,8 @@ private constructor( instruction = executeOptions.instruction highlightCursor = executeOptions.highlightCursor maxSteps = executeOptions.maxSteps + toolTimeout = executeOptions.toolTimeout + useSearch = executeOptions.useSearch additionalProperties = executeOptions.additionalProperties.toMutableMap() } @@ -1832,6 +1878,32 @@ private constructor( */ fun maxSteps(maxSteps: JsonField) = apply { this.maxSteps = maxSteps } + /** Timeout in milliseconds for each agent tool call */ + fun toolTimeout(toolTimeout: Double) = toolTimeout(JsonField.of(toolTimeout)) + + /** + * Sets [Builder.toolTimeout] to an arbitrary JSON value. + * + * You should usually call [Builder.toolTimeout] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun toolTimeout(toolTimeout: JsonField) = apply { + this.toolTimeout = toolTimeout + } + + /** Whether to enable the web search tool powered by Browserbase Search API */ + fun useSearch(useSearch: Boolean) = useSearch(JsonField.of(useSearch)) + + /** + * Sets [Builder.useSearch] to an arbitrary JSON value. + * + * You should usually call [Builder.useSearch] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun useSearch(useSearch: JsonField) = apply { this.useSearch = useSearch } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1868,6 +1940,8 @@ private constructor( checkRequired("instruction", instruction), highlightCursor, maxSteps, + toolTimeout, + useSearch, additionalProperties.toMutableMap(), ) } @@ -1882,6 +1956,8 @@ private constructor( instruction() highlightCursor() maxSteps() + toolTimeout() + useSearch() validated = true } @@ -1903,7 +1979,9 @@ private constructor( internal fun validity(): Int = (if (instruction.asKnown().isPresent) 1 else 0) + (if (highlightCursor.asKnown().isPresent) 1 else 0) + - (if (maxSteps.asKnown().isPresent) 1 else 0) + (if (maxSteps.asKnown().isPresent) 1 else 0) + + (if (toolTimeout.asKnown().isPresent) 1 else 0) + + (if (useSearch.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -1914,17 +1992,26 @@ private constructor( instruction == other.instruction && highlightCursor == other.highlightCursor && maxSteps == other.maxSteps && + toolTimeout == other.toolTimeout && + useSearch == other.useSearch && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(instruction, highlightCursor, maxSteps, additionalProperties) + Objects.hash( + instruction, + highlightCursor, + maxSteps, + toolTimeout, + useSearch, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" + "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, toolTimeout=$toolTimeout, useSearch=$useSearch, additionalProperties=$additionalProperties}" } /** Whether to stream the response via SSE */ diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 695025f..d18eb4a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -14,6 +14,7 @@ import com.browserbase.api.core.allMaxBy import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -566,6 +567,7 @@ private constructor( private val model: JsonField, private val selector: JsonField, private val timeout: JsonField, + private val variables: JsonField, private val additionalProperties: MutableMap, ) { @@ -576,7 +578,10 @@ private constructor( @ExcludeMissing selector: JsonField = JsonMissing.of(), @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), - ) : this(model, selector, timeout, mutableMapOf()) + @JsonProperty("variables") + @ExcludeMissing + variables: JsonField = JsonMissing.of(), + ) : this(model, selector, timeout, variables, mutableMapOf()) /** * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') @@ -602,6 +607,16 @@ private constructor( */ fun timeout(): Optional = timeout.getOptional("timeout") + /** + * Variables whose names are exposed to the model so observe() returns %variableName% + * placeholders in suggested action arguments instead of literal values. Accepts flat + * primitives or { value, description? } objects. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun variables(): Optional = variables.getOptional("variables") + /** * Returns the raw JSON value of [model]. * @@ -623,6 +638,15 @@ private constructor( */ @JsonProperty("timeout") @ExcludeMissing fun _timeout(): JsonField = timeout + /** + * Returns the raw JSON value of [variables]. + * + * Unlike [variables], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("variables") + @ExcludeMissing + fun _variables(): JsonField = variables + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -647,6 +671,7 @@ private constructor( private var model: JsonField = JsonMissing.of() private var selector: JsonField = JsonMissing.of() private var timeout: JsonField = JsonMissing.of() + private var variables: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -654,6 +679,7 @@ private constructor( model = options.model selector = options.selector timeout = options.timeout + variables = options.variables additionalProperties = options.additionalProperties.toMutableMap() } @@ -699,6 +725,22 @@ private constructor( */ fun timeout(timeout: JsonField) = apply { this.timeout = timeout } + /** + * Variables whose names are exposed to the model so observe() returns %variableName% + * placeholders in suggested action arguments instead of literal values. Accepts flat + * primitives or { value, description? } objects. + */ + fun variables(variables: Variables) = variables(JsonField.of(variables)) + + /** + * Sets [Builder.variables] to an arbitrary JSON value. + * + * You should usually call [Builder.variables] with a well-typed [Variables] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun variables(variables: JsonField) = apply { this.variables = variables } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -724,7 +766,7 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): Options = - Options(model, selector, timeout, additionalProperties.toMutableMap()) + Options(model, selector, timeout, variables, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -737,6 +779,7 @@ private constructor( model().ifPresent { it.validate() } selector() timeout() + variables().ifPresent { it.validate() } validated = true } @@ -758,7 +801,8 @@ private constructor( internal fun validity(): Int = (model.asKnown().getOrNull()?.validity() ?: 0) + (if (selector.asKnown().isPresent) 1 else 0) + - (if (timeout.asKnown().isPresent) 1 else 0) + (if (timeout.asKnown().isPresent) 1 else 0) + + (variables.asKnown().getOrNull()?.validity() ?: 0) /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ @JsonDeserialize(using = Model.Deserializer::class) @@ -932,6 +976,113 @@ private constructor( } } + /** + * Variables whose names are exposed to the model so observe() returns %variableName% + * placeholders in suggested action arguments instead of literal values. Accepts flat + * primitives or { value, description? } objects. + */ + class Variables + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Variables]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Variables]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(variables: Variables) = apply { + additionalProperties = variables.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Variables]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Variables = Variables(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Variables = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Variables && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Variables{additionalProperties=$additionalProperties}" + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -941,17 +1092,18 @@ private constructor( model == other.model && selector == other.selector && timeout == other.timeout && + variables == other.variables && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(model, selector, timeout, additionalProperties) + Objects.hash(model, selector, timeout, variables, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" + "Options{model=$model, selector=$selector, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" } /** Whether to stream the response via SSE */ diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 9d1e452..fdfb8dc 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -30,6 +30,15 @@ internal class SessionActParamsTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -72,6 +81,15 @@ internal class SessionActParamsTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -118,6 +136,15 @@ internal class SessionActParamsTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -144,6 +171,15 @@ internal class SessionActParamsTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index cb26cb2..ecf9238 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -44,6 +44,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -108,6 +110,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -176,6 +180,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -217,6 +223,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) assertThat(body.frameId()).contains("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index f238c0e..55d5161 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -27,6 +28,20 @@ internal class SessionObserveParamsTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() @@ -62,6 +77,20 @@ internal class SessionObserveParamsTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() @@ -101,6 +130,20 @@ internal class SessionObserveParamsTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() @@ -122,6 +165,20 @@ internal class SessionObserveParamsTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 33f3131..e9a0664 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -236,6 +236,15 @@ internal class ServiceParamsTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index ce43fba..bfe7ce2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -50,6 +50,15 @@ internal class SessionServiceAsyncTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -93,6 +102,15 @@ internal class SessionServiceAsyncTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -175,6 +193,8 @@ internal class SessionServiceAsyncTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -233,6 +253,8 @@ internal class SessionServiceAsyncTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -397,6 +419,20 @@ internal class SessionServiceAsyncTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() @@ -436,6 +472,20 @@ internal class SessionServiceAsyncTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 3392149..66d2069 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -50,6 +50,15 @@ internal class SessionServiceTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -92,6 +101,15 @@ internal class SessionServiceTest { .variables( SessionActParams.Options.Variables.builder() .putAdditionalProperty("username", JsonValue.from("john_doe")) + .putAdditionalProperty( + "password", + JsonValue.from( + mapOf( + "value" to "secret123", + "description" to "The login password", + ) + ), + ) .build() ) .build() @@ -173,6 +191,8 @@ internal class SessionServiceTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -230,6 +250,8 @@ internal class SessionServiceTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -392,6 +414,20 @@ internal class SessionServiceTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() @@ -430,6 +466,20 @@ internal class SessionServiceTest { ) .selector("nav") .timeout(30000.0) + .variables( + SessionObserveParams.Options.Variables.builder() + .putAdditionalProperty( + "username", + JsonValue.from( + mapOf( + "value" to "john@example.com", + "description" to "The login email", + ) + ), + ) + .putAdditionalProperty("rememberMe", JsonValue.from(true)) + .build() + ) .build() ) .build() From c8d9d2a3a76182dfdaeb3a7a1083f2effec45a2b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 04:31:57 +0000 Subject: [PATCH 135/164] chore(internal): update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b1346e6..90b85e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log .gradle .idea .kotlin From cdd0c3bdd2c1c061fddf1314b21f2b988ce55dba Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 17:21:21 +0000 Subject: [PATCH 136/164] feat: Add explicit SSE event names for local v3 streaming --- .stats.yml | 6 +- .../api/core/handlers/SseHandler.kt | 24 ++----- .../api/models/sessions/StreamEvent.kt | 4 +- .../api/core/handlers/SseHandlerTest.kt | 65 +++++++++++++++---- 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4f6d212..c5e5d8a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-975ca868b31b1e45fb00b31a53d9df1ceec8663f6c2851bf40fdaa84171afadc.yml -openapi_spec_hash: 37891379e0f47e5c69769fbaa1064dab -config_hash: 0209737a4ab2a71afececb0ff7459998 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a4a5ea048bb50d06460d81d6828b53b12b19e9224121ee6338dcd1f0781e22a1.yml +openapi_spec_hash: 9b81c0ae04576318d13d7a80d4ab7b5a +config_hash: d6c6f623d03971bdba921650e5eb7e5f diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt index f8e870e..d0ddde2 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/handlers/SseHandler.kt @@ -18,23 +18,11 @@ import com.fasterxml.jackson.module.kotlin.jacksonTypeRef internal fun sseHandler(jsonMapper: JsonMapper): Handler> = streamHandler { response, lines -> val state = SseState(jsonMapper) - var done = false for (line in lines) { - // Stop emitting messages, but iterate through the full stream. - if (done) { - continue - } - val message = state.decode(line) ?: continue - when { - message.data.startsWith("{\"data\":{\"status\":\"finished\"") -> { - // In this case we don't break because we still want to iterate through the full - // stream. - done = true - continue - } - message.data.startsWith("error") -> { + when (message.event) { + "error" -> { throw SseException.builder() .statusCode(response.statusCode()) .headers(response.headers()) @@ -47,10 +35,10 @@ internal fun sseHandler(jsonMapper: JsonMapper): Handler yield(message) } } } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt index 443104b..4584374 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -30,8 +30,8 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. Key - * order: data (with status first), type, id. + * Server-Sent Event emitted during streaming responses. Events are sent as `event: \ndata: + * \n\n`, where the JSON payload has the shape `{ data, type, id }`. */ class StreamEvent @JsonCreator(mode = JsonCreator.Mode.DISABLED) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt index 29105f3..2e4dfb0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/handlers/SseHandlerTest.kt @@ -2,10 +2,12 @@ package com.browserbase.api.core.handlers +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpResponse import com.browserbase.api.core.http.SseMessage import com.browserbase.api.core.jsonMapper +import com.browserbase.api.errors.SseException import java.io.InputStream import java.util.stream.Collectors.toList import org.assertj.core.api.Assertions.assertThat @@ -21,64 +23,105 @@ internal class SseHandlerTest { internal val expectedMessages: List? = null, internal val expectedException: Exception? = null, ) { - DATA_MISSING_EVENT( + EVENT_AND_DATA( buildString { + append("event: starting\n") append("data: {\"foo\":true}\n") append("\n") }, - listOf(sseMessageBuilder().data("{\"foo\":true}").build()), + listOf(sseMessageBuilder().event("starting").data("{\"foo\":true}").build()), ), - MULTIPLE_DATA_MISSING_EVENT( + EVENT_MISSING_DATA( buildString { + append("event: starting\n") + append("\n") + }, + listOf(sseMessageBuilder().event("starting").build()), + ), + MULTIPLE_EVENTS_AND_DATA( + buildString { + append("event: starting\n") append("data: {\"foo\":true}\n") append("\n") + append("event: connected\n") append("data: {\"bar\":false}\n") append("\n") }, listOf( - sseMessageBuilder().data("{\"foo\":true}").build(), - sseMessageBuilder().data("{\"bar\":false}").build(), + sseMessageBuilder().event("starting").data("{\"foo\":true}").build(), + sseMessageBuilder().event("connected").data("{\"bar\":false}").build(), + ), + ), + MULTIPLE_EVENTS_MISSING_DATA( + buildString { + append("event: starting\n") + append("\n") + append("event: connected\n") + append("\n") + }, + listOf( + sseMessageBuilder().event("starting").build(), + sseMessageBuilder().event("connected").build(), ), ), DATA_JSON_ESCAPED_DOUBLE_NEW_LINE( buildString { + append("event: starting\n") append("data: {\n") append("data: \"foo\":\n") append("data: true}\n") append("\n\n") }, - listOf(sseMessageBuilder().data("{\n\"foo\":\ntrue}").build()), + listOf(sseMessageBuilder().event("starting").data("{\n\"foo\":\ntrue}").build()), ), MULTIPLE_DATA_LINES( buildString { + append("event: starting\n") append("data: {\n") append("data: \"foo\":\n") append("data: true}\n") append("\n\n") }, - listOf(sseMessageBuilder().data("{\n\"foo\":\ntrue}").build()), + listOf(sseMessageBuilder().event("starting").data("{\n\"foo\":\ntrue}").build()), ), SPECIAL_NEW_LINE_CHARACTER( buildString { + append("event: starting\n") append("data: {\"content\":\" culpa\"}\n") append("\n") + append("event: connected\n") append("data: {\"content\":\" \u2028\"}\n") append("\n") + append("event: starting\n") append("data: {\"content\":\"foo\"}\n") append("\n") }, listOf( - sseMessageBuilder().data("{\"content\":\" culpa\"}").build(), - sseMessageBuilder().data("{\"content\":\" \u2028\"}").build(), - sseMessageBuilder().data("{\"content\":\"foo\"}").build(), + sseMessageBuilder().event("starting").data("{\"content\":\" culpa\"}").build(), + sseMessageBuilder().event("connected").data("{\"content\":\" \u2028\"}").build(), + sseMessageBuilder().event("starting").data("{\"content\":\"foo\"}").build(), ), ), MULTI_BYTE_CHARACTER( buildString { + append("event: starting\n") append("data: {\"content\":\"\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0438\"}\n") append("\n") }, - listOf(sseMessageBuilder().data("{\"content\":\"известни\"}").build()), + listOf(sseMessageBuilder().event("starting").data("{\"content\":\"известни\"}").build()), + ), + ERROR_EVENT( + buildString { + append("event: error\n") + append("data: {\"errorProperty\":\"42\"}\n") + append("\n") + }, + expectedException = + SseException.builder() + .statusCode(0) + .headers(Headers.builder().build()) + .body(JsonValue.from(mapOf("errorProperty" to "42"))) + .build(), ), } From 0c89d2aa4db4fd4d550a3a404d842e3a59ee8bfc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:30:14 +0000 Subject: [PATCH 137/164] feat: Include LLM headers in ModelConfig --- .stats.yml | 4 +- .../api/models/sessions/ModelConfig.kt | 141 +++++++++++++++++- .../api/models/sessions/ModelConfigTest.kt | 17 +++ .../models/sessions/SessionActParamsTest.kt | 20 +++ .../sessions/SessionExecuteParamsTest.kt | 41 +++++ .../sessions/SessionExtractParamsTest.kt | 20 +++ .../sessions/SessionObserveParamsTest.kt | 20 +++ .../api/services/ServiceParamsTest.kt | 5 + .../services/async/SessionServiceAsyncTest.kt | 50 +++++++ .../services/blocking/SessionServiceTest.kt | 50 +++++++ 10 files changed, 363 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index c5e5d8a..129faad 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a4a5ea048bb50d06460d81d6828b53b12b19e9224121ee6338dcd1f0781e22a1.yml -openapi_spec_hash: 9b81c0ae04576318d13d7a80d4ab7b5a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-bc309fd00fe0507f4cbe3bc77fa27d0fbffeaa6e71998778da34de42608a67e8.yml +openapi_spec_hash: 1db1af5c1b068bba1d652102f4454668 config_hash: d6c6f623d03971bdba921650e5eb7e5f diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 1334949..4e46131 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -8,6 +8,7 @@ import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -24,6 +25,7 @@ private constructor( private val modelName: JsonField, private val apiKey: JsonField, private val baseUrl: JsonField, + private val headers: JsonField, private val provider: JsonField, private val additionalProperties: MutableMap, ) { @@ -33,8 +35,9 @@ private constructor( @JsonProperty("modelName") @ExcludeMissing modelName: JsonField = JsonMissing.of(), @JsonProperty("apiKey") @ExcludeMissing apiKey: JsonField = JsonMissing.of(), @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), + @JsonProperty("headers") @ExcludeMissing headers: JsonField = JsonMissing.of(), @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), - ) : this(modelName, apiKey, baseUrl, provider, mutableMapOf()) + ) : this(modelName, apiKey, baseUrl, headers, provider, mutableMapOf()) /** * Model name string with provider prefix (e.g., 'openai/gpt-5-nano') @@ -60,6 +63,14 @@ private constructor( */ fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + /** + * Custom headers sent with every request to the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun headers(): Optional = headers.getOptional("headers") + /** * AI provider for the model (or provide a baseURL endpoint instead) * @@ -89,6 +100,13 @@ private constructor( */ @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + /** + * Returns the raw JSON value of [headers]. + * + * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers + /** * Returns the raw JSON value of [provider]. * @@ -127,6 +145,7 @@ private constructor( private var modelName: JsonField? = null private var apiKey: JsonField = JsonMissing.of() private var baseUrl: JsonField = JsonMissing.of() + private var headers: JsonField = JsonMissing.of() private var provider: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -135,6 +154,7 @@ private constructor( modelName = modelConfig.modelName apiKey = modelConfig.apiKey baseUrl = modelConfig.baseUrl + headers = modelConfig.headers provider = modelConfig.provider additionalProperties = modelConfig.additionalProperties.toMutableMap() } @@ -173,6 +193,17 @@ private constructor( */ fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + /** Custom headers sent with every request to the model provider */ + fun headers(headers: Headers) = headers(JsonField.of(headers)) + + /** + * Sets [Builder.headers] to an arbitrary JSON value. + * + * You should usually call [Builder.headers] with a well-typed [Headers] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun headers(headers: JsonField) = apply { this.headers = headers } + /** AI provider for the model (or provide a baseURL endpoint instead) */ fun provider(provider: Provider) = provider(JsonField.of(provider)) @@ -221,6 +252,7 @@ private constructor( checkRequired("modelName", modelName), apiKey, baseUrl, + headers, provider, additionalProperties.toMutableMap(), ) @@ -236,6 +268,7 @@ private constructor( modelName() apiKey() baseUrl() + headers().ifPresent { it.validate() } provider().ifPresent { it.validate() } validated = true } @@ -258,8 +291,109 @@ private constructor( (if (modelName.asKnown().isPresent) 1 else 0) + (if (apiKey.asKnown().isPresent) 1 else 0) + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (headers.asKnown().getOrNull()?.validity() ?: 0) + (provider.asKnown().getOrNull()?.validity() ?: 0) + /** Custom headers sent with every request to the model provider */ + class Headers + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Headers]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Headers]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(headers: Headers) = apply { + additionalProperties = headers.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Headers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Headers = Headers(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Headers = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Headers{additionalProperties=$additionalProperties}" + } + /** AI provider for the model (or provide a baseURL endpoint instead) */ class Provider @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -415,16 +549,17 @@ private constructor( modelName == other.modelName && apiKey == other.apiKey && baseUrl == other.baseUrl && + headers == other.headers && provider == other.provider && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(modelName, apiKey, baseUrl, provider, additionalProperties) + Objects.hash(modelName, apiKey, baseUrl, headers, provider, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, provider=$provider, additionalProperties=$additionalProperties}" + "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, provider=$provider, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index cd7f6b7..ee341a1 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import org.assertj.core.api.Assertions.assertThat @@ -16,12 +17,23 @@ internal class ModelConfigTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5-nano") assertThat(modelConfig.apiKey()).contains("sk-some-openai-api-key") assertThat(modelConfig.baseUrl()).contains("https://api.openai.com/v1") + assertThat(modelConfig.headers()) + .contains( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI) } @@ -33,6 +45,11 @@ internal class ModelConfigTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index fdfb8dc..86e9f29 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -23,6 +23,11 @@ internal class SessionActParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -74,6 +79,11 @@ internal class SessionActParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -129,6 +139,11 @@ internal class SessionActParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -164,6 +179,11 @@ internal class SessionActParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index ecf9238..dc042b7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -2,6 +2,7 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.JsonValue import com.browserbase.api.core.http.Headers import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -21,6 +22,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -30,6 +36,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -87,6 +98,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -96,6 +112,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -157,6 +178,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -166,6 +192,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -199,6 +230,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -208,6 +244,11 @@ internal class SessionExecuteParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 3061c8d..1418be5 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -23,6 +23,11 @@ internal class SessionExtractParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -63,6 +68,11 @@ internal class SessionExtractParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -107,6 +117,11 @@ internal class SessionExtractParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -134,6 +149,11 @@ internal class SessionExtractParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 55d5161..1ed125e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -23,6 +23,11 @@ internal class SessionObserveParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -72,6 +77,11 @@ internal class SessionObserveParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -125,6 +135,11 @@ internal class SessionObserveParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -160,6 +175,11 @@ internal class SessionObserveParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index e9a0664..3f10c1a 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -229,6 +229,11 @@ internal class ServiceParamsTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index bfe7ce2..471a7ac 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -43,6 +43,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -95,6 +100,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -170,6 +180,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -179,6 +194,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -230,6 +250,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -239,6 +264,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -292,6 +322,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -336,6 +371,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -414,6 +454,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -467,6 +512,11 @@ internal class SessionServiceAsyncTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 66d2069..e6c5cb5 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -43,6 +43,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -94,6 +99,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -168,6 +178,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -177,6 +192,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -227,6 +247,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -236,6 +261,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -289,6 +319,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -332,6 +367,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -409,6 +449,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) @@ -461,6 +506,11 @@ internal class SessionServiceTest { .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") + .headers( + ModelConfig.Headers.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .provider(ModelConfig.Provider.OPENAI) .build() ) From cefc4afe891dbbeb97e3db2bf13c5e50d0bef51a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 03:19:44 +0000 Subject: [PATCH 138/164] chore(ci): skip lint on metadata-only changes Note that we still want to run tests, as these depend on the metadata. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a2d45c..a8d4c5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: timeout-minutes: 15 name: lint runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + 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@v6 @@ -46,7 +46,7 @@ jobs: contents: read id-token: write runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + 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@v6 From 53cdf0cf283fe6842b6e6358f53ce9ebde4a7005 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 23:17:51 +0000 Subject: [PATCH 139/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1bc5713..df3292b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.7.1" + ".": "3.18.0" } \ No newline at end of file diff --git a/README.md b/README.md index b560f82..4cbe7c7 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/0.7.1) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/0.7.1/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.1) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/3.18.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/3.18.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.18.0) @@ -15,7 +15,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/0.7.1). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.18.0). @@ -26,7 +26,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:0.7.1") +implementation("com.browserbase.api:stagehand-java:3.18.0") ``` ### Maven @@ -35,7 +35,7 @@ implementation("com.browserbase.api:stagehand-java:0.7.1") com.browserbase.api stagehand-java - 0.7.1 + 3.18.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index 79fb854..e4d25aa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "0.7.1" // x-release-please-version + version = "3.18.0" // x-release-please-version } subprojects { From a8dec7a078e4ad81a8d808ff9c2ab7a7c67a3ad1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:18:23 +0000 Subject: [PATCH 140/164] feat: Replace default model used in server-v3 api spec examples --- .stats.yml | 6 ++-- README.md | 2 +- .../api/models/sessions/ModelConfigTest.kt | 6 ++-- .../models/sessions/SessionActParamsTest.kt | 8 ++--- .../sessions/SessionExecuteParamsTest.kt | 16 ++++----- .../sessions/SessionExtractParamsTest.kt | 8 ++--- .../sessions/SessionObserveParamsTest.kt | 8 ++--- .../models/sessions/SessionStartParamsTest.kt | 14 ++++---- .../api/services/ErrorHandlingTest.kt | 34 +++++++++---------- .../api/services/ServiceParamsTest.kt | 4 +-- .../services/async/SessionServiceAsyncTest.kt | 22 ++++++------ .../services/blocking/SessionServiceTest.kt | 22 ++++++------ 12 files changed, 75 insertions(+), 75 deletions(-) diff --git a/.stats.yml b/.stats.yml index 129faad..ac9e78a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-bc309fd00fe0507f4cbe3bc77fa27d0fbffeaa6e71998778da34de42608a67e8.yml -openapi_spec_hash: 1db1af5c1b068bba1d652102f4454668 -config_hash: d6c6f623d03971bdba921650e5eb7e5f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-b969ce378479c79ee64c05127c0ed6c6ce2edbee017ecd037242fb618a5ebc9f.yml +openapi_spec_hash: a24aabaa5214effb679808b7f2be0ad4 +config_hash: a962ae71493deb11a1c903256fb25386 diff --git a/README.md b/README.md index 4cbe7c7..dab9fdd 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ import com.browserbase.api.models.sessions.SessionStartParams; import com.browserbase.api.models.sessions.SessionStartResponse; SessionStartParams params = SessionStartParams.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .build(); HttpResponseFor response = client.sessions().withRawResponse().start(params); diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index ee341a1..6e3b3d0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -14,7 +14,7 @@ internal class ModelConfigTest { fun create() { val modelConfig = ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -25,7 +25,7 @@ internal class ModelConfigTest { .provider(ModelConfig.Provider.OPENAI) .build() - assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5-nano") + assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5.4-mini") assertThat(modelConfig.apiKey()).contains("sk-some-openai-api-key") assertThat(modelConfig.baseUrl()).contains("https://api.openai.com/v1") assertThat(modelConfig.headers()) @@ -42,7 +42,7 @@ internal class ModelConfigTest { val jsonMapper = jsonMapper() val modelConfig = ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 86e9f29..31ef59b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -20,7 +20,7 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -76,7 +76,7 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -136,7 +136,7 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -176,7 +176,7 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index dc042b7..f040cad 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -19,7 +19,7 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -33,7 +33,7 @@ internal class SessionExecuteParamsTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -95,7 +95,7 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -109,7 +109,7 @@ internal class SessionExecuteParamsTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -175,7 +175,7 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -189,7 +189,7 @@ internal class SessionExecuteParamsTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -227,7 +227,7 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -241,7 +241,7 @@ internal class SessionExecuteParamsTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index 1418be5..d84a3f9 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -20,7 +20,7 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -65,7 +65,7 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -114,7 +114,7 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -146,7 +146,7 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 1ed125e..08f0c13 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -20,7 +20,7 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -74,7 +74,7 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -132,7 +132,7 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -172,7 +172,7 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 5b35aaa..7ebe44e 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -13,7 +13,7 @@ internal class SessionStartParamsTest { fun create() { SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -164,7 +164,7 @@ internal class SessionStartParamsTest { val params = SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -320,7 +320,7 @@ internal class SessionStartParamsTest { @Test fun headersWithoutOptionalFields() { - val params = SessionStartParams.builder().modelName("openai/gpt-4o").build() + val params = SessionStartParams.builder().modelName("openai/gpt-5.4-mini").build() val headers = params._headers() @@ -332,7 +332,7 @@ internal class SessionStartParamsTest { val params = SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -483,7 +483,7 @@ internal class SessionStartParamsTest { val body = params._body() - assertThat(body.modelName()).isEqualTo("openai/gpt-4o") + assertThat(body.modelName()).isEqualTo("openai/gpt-5.4-mini") assertThat(body.actTimeoutMs()).contains(0.0) assertThat(body.browser()) .contains( @@ -632,10 +632,10 @@ internal class SessionStartParamsTest { @Test fun bodyWithoutOptionalFields() { - val params = SessionStartParams.builder().modelName("openai/gpt-4o").build() + val params = SessionStartParams.builder().modelName("openai/gpt-5.4-mini").build() val body = params._body() - assertThat(body.modelName()).isEqualTo("openai/gpt-4o") + assertThat(body.modelName()).isEqualTo("openai/gpt-5.4-mini") } } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index a123b5c..a3bc8a0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -75,7 +75,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -261,7 +261,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -447,7 +447,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -633,7 +633,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -819,7 +819,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1005,7 +1005,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1191,7 +1191,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1377,7 +1377,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1563,7 +1563,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1749,7 +1749,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -1935,7 +1935,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2121,7 +2121,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2307,7 +2307,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2493,7 +2493,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2679,7 +2679,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -2865,7 +2865,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -3049,7 +3049,7 @@ internal class ErrorHandlingTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 3f10c1a..f423bd2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -49,7 +49,7 @@ internal class ServiceParamsTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() @@ -226,7 +226,7 @@ internal class ServiceParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 471a7ac..3635e44 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -40,7 +40,7 @@ internal class SessionServiceAsyncTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -97,7 +97,7 @@ internal class SessionServiceAsyncTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -177,7 +177,7 @@ internal class SessionServiceAsyncTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -191,7 +191,7 @@ internal class SessionServiceAsyncTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -247,7 +247,7 @@ internal class SessionServiceAsyncTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -261,7 +261,7 @@ internal class SessionServiceAsyncTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -319,7 +319,7 @@ internal class SessionServiceAsyncTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -368,7 +368,7 @@ internal class SessionServiceAsyncTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -451,7 +451,7 @@ internal class SessionServiceAsyncTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -509,7 +509,7 @@ internal class SessionServiceAsyncTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -584,7 +584,7 @@ internal class SessionServiceAsyncTest { sessionServiceAsync.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index e6c5cb5..15ae6c4 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -40,7 +40,7 @@ internal class SessionServiceTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -96,7 +96,7 @@ internal class SessionServiceTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -175,7 +175,7 @@ internal class SessionServiceTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -189,7 +189,7 @@ internal class SessionServiceTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -244,7 +244,7 @@ internal class SessionServiceTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -258,7 +258,7 @@ internal class SessionServiceTest { .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -316,7 +316,7 @@ internal class SessionServiceTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -364,7 +364,7 @@ internal class SessionServiceTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -446,7 +446,7 @@ internal class SessionServiceTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -503,7 +503,7 @@ internal class SessionServiceTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( @@ -577,7 +577,7 @@ internal class SessionServiceTest { sessionService.start( SessionStartParams.builder() .xStreamResponse(SessionStartParams.XStreamResponse.TRUE) - .modelName("openai/gpt-4o") + .modelName("openai/gpt-5.4-mini") .actTimeoutMs(0.0) .browser( SessionStartParams.Browser.builder() From d847705ad68653ec1ed358ff42ce1a4229b0b91f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:30:19 +0000 Subject: [PATCH 141/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index df3292b..911c623 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.18.0" + ".": "3.19.3" } \ No newline at end of file diff --git a/README.md b/README.md index dab9fdd..f65c2e2 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/3.18.0) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/3.18.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.18.0) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/3.19.3) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/3.19.3/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.19.3) @@ -15,7 +15,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.18.0). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.19.3). @@ -26,7 +26,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:3.18.0") +implementation("com.browserbase.api:stagehand-java:3.19.3") ``` ### Maven @@ -35,7 +35,7 @@ implementation("com.browserbase.api:stagehand-java:3.18.0") com.browserbase.api stagehand-java - 3.18.0 + 3.19.3 ``` diff --git a/build.gradle.kts b/build.gradle.kts index e4d25aa..7d91da7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "3.18.0" // x-release-please-version + version = "3.19.3" // x-release-please-version } subprojects { From d532b945923f65d6275bf09f7de177e3da2d5272 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:38:43 +0000 Subject: [PATCH 142/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index ac9e78a..ade26eb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-b969ce378479c79ee64c05127c0ed6c6ce2edbee017ecd037242fb618a5ebc9f.yml openapi_spec_hash: a24aabaa5214effb679808b7f2be0ad4 -config_hash: a962ae71493deb11a1c903256fb25386 +config_hash: 0cc516caf1432087f40654336e0fa8cd From 8ccdbd1c663899fc0df468e11f99c2b7d0045fe6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 18:22:46 +0000 Subject: [PATCH 143/164] feat: Bedrock auth passthrough --- .stats.yml | 4 +- .../api/models/sessions/ModelConfig.kt | 1987 +++++++- .../models/sessions/SessionExecuteParams.kt | 97 +- .../api/models/sessions/SessionStartParams.kt | 4089 ++++++++++++++++- .../api/models/sessions/StreamEvent.kt | 4 +- .../api/models/sessions/ModelConfigTest.kt | 33 +- .../models/sessions/SessionActParamsTest.kt | 54 +- .../sessions/SessionExecuteParamsTest.kt | 116 +- .../sessions/SessionExtractParamsTest.kt | 54 +- .../sessions/SessionObserveParamsTest.kt | 54 +- .../models/sessions/SessionStartParamsTest.kt | 87 + .../api/services/ErrorHandlingTest.kt | 459 ++ .../api/services/ServiceParamsTest.kt | 35 +- .../services/async/SessionServiceAsyncTest.kt | 171 +- .../services/blocking/SessionServiceTest.kt | 171 +- 15 files changed, 7207 insertions(+), 208 deletions(-) diff --git a/.stats.yml b/.stats.yml index ade26eb..f1d6429 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-b969ce378479c79ee64c05127c0ed6c6ce2edbee017ecd037242fb618a5ebc9f.yml -openapi_spec_hash: a24aabaa5214effb679808b7f2be0ad4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-7773ef4ca29c983daafb787ee918cfa6b5b12c5bbdc088308653f2737c26e51f.yml +openapi_spec_hash: 47fc8f2540be0b6374e4230c021072d9 config_hash: 0cc516caf1432087f40654336e0fa8cd diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 4e46131..c397bfa 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -2,18 +2,29 @@ package com.browserbase.api.models.sessions +import com.browserbase.api.core.BaseDeserializer +import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue +import com.browserbase.api.core.allMaxBy import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional @@ -27,6 +38,8 @@ private constructor( private val baseUrl: JsonField, private val headers: JsonField, private val provider: JsonField, + private val providerOptions: JsonField, + private val skipApiKeyFallback: JsonField, private val additionalProperties: MutableMap, ) { @@ -37,7 +50,22 @@ private constructor( @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), @JsonProperty("headers") @ExcludeMissing headers: JsonField = JsonMissing.of(), @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), - ) : this(modelName, apiKey, baseUrl, headers, provider, mutableMapOf()) + @JsonProperty("providerOptions") + @ExcludeMissing + providerOptions: JsonField = JsonMissing.of(), + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + skipApiKeyFallback: JsonField = JsonMissing.of(), + ) : this( + modelName, + apiKey, + baseUrl, + headers, + provider, + providerOptions, + skipApiKeyFallback, + mutableMapOf(), + ) /** * Model name string with provider prefix (e.g., 'openai/gpt-5-nano') @@ -64,7 +92,7 @@ private constructor( fun baseUrl(): Optional = baseUrl.getOptional("baseURL") /** - * Custom headers sent with every request to the model provider + * Custom headers for the model provider * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -79,6 +107,27 @@ private constructor( */ fun provider(): Optional = provider.getOptional("provider") + /** + * Provider-specific options passed through to the AI SDK provider constructor. For Bedrock: { + * region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { project, location, + * googleAuthOptions }. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun providerOptions(): Optional = + providerOptions.getOptional("providerOptions") + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this when + * auth is carried through providerOptions instead of an API key. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun skipApiKeyFallback(): Optional = + skipApiKeyFallback.getOptional("skipApiKeyFallback") + /** * Returns the raw JSON value of [modelName]. * @@ -114,6 +163,25 @@ private constructor( */ @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider + /** + * Returns the raw JSON value of [providerOptions]. + * + * Unlike [providerOptions], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("providerOptions") + @ExcludeMissing + fun _providerOptions(): JsonField = providerOptions + + /** + * Returns the raw JSON value of [skipApiKeyFallback]. + * + * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -147,6 +215,8 @@ private constructor( private var baseUrl: JsonField = JsonMissing.of() private var headers: JsonField = JsonMissing.of() private var provider: JsonField = JsonMissing.of() + private var providerOptions: JsonField = JsonMissing.of() + private var skipApiKeyFallback: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -156,6 +226,8 @@ private constructor( baseUrl = modelConfig.baseUrl headers = modelConfig.headers provider = modelConfig.provider + providerOptions = modelConfig.providerOptions + skipApiKeyFallback = modelConfig.skipApiKeyFallback additionalProperties = modelConfig.additionalProperties.toMutableMap() } @@ -193,7 +265,7 @@ private constructor( */ fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - /** Custom headers sent with every request to the model provider */ + /** Custom headers for the model provider */ fun headers(headers: Headers) = headers(JsonField.of(headers)) /** @@ -216,6 +288,64 @@ private constructor( */ fun provider(provider: JsonField) = apply { this.provider = provider } + /** + * Provider-specific options passed through to the AI SDK provider constructor. For Bedrock: + * { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { project, location, + * googleAuthOptions }. + */ + fun providerOptions(providerOptions: ProviderOptions) = + providerOptions(JsonField.of(providerOptions)) + + /** + * Sets [Builder.providerOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.providerOptions] with a well-typed [ProviderOptions] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun providerOptions(providerOptions: JsonField) = apply { + this.providerOptions = providerOptions + } + + /** + * Alias for calling [providerOptions] with + * `ProviderOptions.ofBedrockApiKey(bedrockApiKey)`. + */ + fun providerOptions(bedrockApiKey: ProviderOptions.BedrockApiKeyProviderOptions) = + providerOptions(ProviderOptions.ofBedrockApiKey(bedrockApiKey)) + + /** + * Alias for calling [providerOptions] with + * `ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. + */ + fun providerOptions( + bedrockAwsCredentials: ProviderOptions.BedrockAwsCredentialsProviderOptions + ) = providerOptions(ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)) + + /** + * Alias for calling [providerOptions] with `ProviderOptions.ofGoogleVertex(googleVertex)`. + */ + fun providerOptions(googleVertex: ProviderOptions.GoogleVertexProviderOptions) = + providerOptions(ProviderOptions.ofGoogleVertex(googleVertex)) + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this when + * auth is carried through providerOptions instead of an API key. + */ + fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = + skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) + + /** + * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. + * + * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { + this.skipApiKeyFallback = skipApiKeyFallback + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -254,6 +384,8 @@ private constructor( baseUrl, headers, provider, + providerOptions, + skipApiKeyFallback, additionalProperties.toMutableMap(), ) } @@ -270,6 +402,8 @@ private constructor( baseUrl() headers().ifPresent { it.validate() } provider().ifPresent { it.validate() } + providerOptions().ifPresent { it.validate() } + skipApiKeyFallback() validated = true } @@ -292,9 +426,11 @@ private constructor( (if (apiKey.asKnown().isPresent) 1 else 0) + (if (baseUrl.asKnown().isPresent) 1 else 0) + (headers.asKnown().getOrNull()?.validity() ?: 0) + - (provider.asKnown().getOrNull()?.validity() ?: 0) + (provider.asKnown().getOrNull()?.validity() ?: 0) + + (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) - /** Custom headers sent with every request to the model provider */ + /** Custom headers for the model provider */ class Headers @JsonCreator private constructor( @@ -540,6 +676,1832 @@ private constructor( override fun toString() = value.toString() } + /** + * Provider-specific options passed through to the AI SDK provider constructor. For Bedrock: { + * region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { project, location, + * googleAuthOptions }. + */ + @JsonDeserialize(using = ProviderOptions.Deserializer::class) + @JsonSerialize(using = ProviderOptions.Serializer::class) + class ProviderOptions + private constructor( + private val bedrockApiKey: BedrockApiKeyProviderOptions? = null, + private val bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions? = null, + private val googleVertex: GoogleVertexProviderOptions? = null, + private val _json: JsonValue? = null, + ) { + + fun bedrockApiKey(): Optional = + Optional.ofNullable(bedrockApiKey) + + fun bedrockAwsCredentials(): Optional = + Optional.ofNullable(bedrockAwsCredentials) + + fun googleVertex(): Optional = + Optional.ofNullable(googleVertex) + + fun isBedrockApiKey(): Boolean = bedrockApiKey != null + + fun isBedrockAwsCredentials(): Boolean = bedrockAwsCredentials != null + + fun isGoogleVertex(): Boolean = googleVertex != null + + fun asBedrockApiKey(): BedrockApiKeyProviderOptions = + bedrockApiKey.getOrThrow("bedrockApiKey") + + fun asBedrockAwsCredentials(): BedrockAwsCredentialsProviderOptions = + bedrockAwsCredentials.getOrThrow("bedrockAwsCredentials") + + fun asGoogleVertex(): GoogleVertexProviderOptions = googleVertex.getOrThrow("googleVertex") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + bedrockApiKey != null -> visitor.visitBedrockApiKey(bedrockApiKey) + bedrockAwsCredentials != null -> + visitor.visitBedrockAwsCredentials(bedrockAwsCredentials) + googleVertex != null -> visitor.visitGoogleVertex(googleVertex) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ProviderOptions = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) { + bedrockApiKey.validate() + } + + override fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ) { + bedrockAwsCredentials.validate() + } + + override fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions) { + googleVertex.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) = + bedrockApiKey.validity() + + override fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ) = bedrockAwsCredentials.validity() + + override fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions) = + googleVertex.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProviderOptions && + bedrockApiKey == other.bedrockApiKey && + bedrockAwsCredentials == other.bedrockAwsCredentials && + googleVertex == other.googleVertex + } + + override fun hashCode(): Int = + Objects.hash(bedrockApiKey, bedrockAwsCredentials, googleVertex) + + override fun toString(): String = + when { + bedrockApiKey != null -> "ProviderOptions{bedrockApiKey=$bedrockApiKey}" + bedrockAwsCredentials != null -> + "ProviderOptions{bedrockAwsCredentials=$bedrockAwsCredentials}" + googleVertex != null -> "ProviderOptions{googleVertex=$googleVertex}" + _json != null -> "ProviderOptions{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ProviderOptions") + } + + companion object { + + @JvmStatic + fun ofBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) = + ProviderOptions(bedrockApiKey = bedrockApiKey) + + @JvmStatic + fun ofBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ) = ProviderOptions(bedrockAwsCredentials = bedrockAwsCredentials) + + @JvmStatic + fun ofGoogleVertex(googleVertex: GoogleVertexProviderOptions) = + ProviderOptions(googleVertex = googleVertex) + } + + /** + * An interface that defines how to map each variant of [ProviderOptions] to a value of type + * [T]. + */ + interface Visitor { + + fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions): T + + fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ): T + + fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions): T + + /** + * Maps an unknown variant of [ProviderOptions] to a value of type [T]. + * + * An instance of [ProviderOptions] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown ProviderOptions: $json") + } + } + + internal class Deserializer : BaseDeserializer(ProviderOptions::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ProviderOptions { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { ProviderOptions(bedrockApiKey = it, _json = json) }, + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { ProviderOptions(bedrockAwsCredentials = it, _json = json) }, + tryDeserialize(node, jacksonTypeRef()) + ?.let { ProviderOptions(googleVertex = it, _json = json) }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> ProviderOptions(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(ProviderOptions::class) { + + override fun serialize( + value: ProviderOptions, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.bedrockApiKey != null -> generator.writeObject(value.bedrockApiKey) + value.bedrockAwsCredentials != null -> + generator.writeObject(value.bedrockAwsCredentials) + value.googleVertex != null -> generator.writeObject(value.googleVertex) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ProviderOptions") + } + } + } + + class BedrockApiKeyProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val region: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("region") @ExcludeMissing region: JsonField = JsonMissing.of() + ) : this(region, mutableMapOf()) + + /** + * AWS region for Amazon Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun region(): String = region.getRequired("region") + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BedrockApiKeyProviderOptions]. + * + * The following fields are required: + * ```java + * .region() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BedrockApiKeyProviderOptions]. */ + class Builder internal constructor() { + + private var region: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(bedrockApiKeyProviderOptions: BedrockApiKeyProviderOptions) = + apply { + region = bedrockApiKeyProviderOptions.region + additionalProperties = + bedrockApiKeyProviderOptions.additionalProperties.toMutableMap() + } + + /** AWS region for Amazon Bedrock */ + fun region(region: String) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BedrockApiKeyProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .region() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BedrockApiKeyProviderOptions = + BedrockApiKeyProviderOptions( + checkRequired("region", region), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BedrockApiKeyProviderOptions = apply { + if (validated) { + return@apply + } + + region() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (if (region.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BedrockApiKeyProviderOptions && + region == other.region && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(region, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BedrockApiKeyProviderOptions{region=$region, additionalProperties=$additionalProperties}" + } + + class BedrockAwsCredentialsProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val accessKeyId: JsonField, + private val region: JsonField, + private val secretAccessKey: JsonField, + private val sessionToken: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("accessKeyId") + @ExcludeMissing + accessKeyId: JsonField = JsonMissing.of(), + @JsonProperty("region") + @ExcludeMissing + region: JsonField = JsonMissing.of(), + @JsonProperty("secretAccessKey") + @ExcludeMissing + secretAccessKey: JsonField = JsonMissing.of(), + @JsonProperty("sessionToken") + @ExcludeMissing + sessionToken: JsonField = JsonMissing.of(), + ) : this(accessKeyId, region, secretAccessKey, sessionToken, mutableMapOf()) + + /** + * AWS access key ID for Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun accessKeyId(): String = accessKeyId.getRequired("accessKeyId") + + /** + * AWS region for Amazon Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun region(): String = region.getRequired("region") + + /** + * AWS secret access key for Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun secretAccessKey(): String = secretAccessKey.getRequired("secretAccessKey") + + /** + * Optional AWS session token for temporary credentials + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun sessionToken(): Optional = sessionToken.getOptional("sessionToken") + + /** + * Returns the raw JSON value of [accessKeyId]. + * + * Unlike [accessKeyId], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("accessKeyId") + @ExcludeMissing + fun _accessKeyId(): JsonField = accessKeyId + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region + + /** + * Returns the raw JSON value of [secretAccessKey]. + * + * Unlike [secretAccessKey], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("secretAccessKey") + @ExcludeMissing + fun _secretAccessKey(): JsonField = secretAccessKey + + /** + * Returns the raw JSON value of [sessionToken]. + * + * Unlike [sessionToken], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("sessionToken") + @ExcludeMissing + fun _sessionToken(): JsonField = sessionToken + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BedrockAwsCredentialsProviderOptions]. + * + * The following fields are required: + * ```java + * .accessKeyId() + * .region() + * .secretAccessKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BedrockAwsCredentialsProviderOptions]. */ + class Builder internal constructor() { + + private var accessKeyId: JsonField? = null + private var region: JsonField? = null + private var secretAccessKey: JsonField? = null + private var sessionToken: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from( + bedrockAwsCredentialsProviderOptions: BedrockAwsCredentialsProviderOptions + ) = apply { + accessKeyId = bedrockAwsCredentialsProviderOptions.accessKeyId + region = bedrockAwsCredentialsProviderOptions.region + secretAccessKey = bedrockAwsCredentialsProviderOptions.secretAccessKey + sessionToken = bedrockAwsCredentialsProviderOptions.sessionToken + additionalProperties = + bedrockAwsCredentialsProviderOptions.additionalProperties.toMutableMap() + } + + /** AWS access key ID for Bedrock */ + fun accessKeyId(accessKeyId: String) = accessKeyId(JsonField.of(accessKeyId)) + + /** + * Sets [Builder.accessKeyId] to an arbitrary JSON value. + * + * You should usually call [Builder.accessKeyId] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun accessKeyId(accessKeyId: JsonField) = apply { + this.accessKeyId = accessKeyId + } + + /** AWS region for Amazon Bedrock */ + fun region(region: String) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + /** AWS secret access key for Bedrock */ + fun secretAccessKey(secretAccessKey: String) = + secretAccessKey(JsonField.of(secretAccessKey)) + + /** + * Sets [Builder.secretAccessKey] to an arbitrary JSON value. + * + * You should usually call [Builder.secretAccessKey] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun secretAccessKey(secretAccessKey: JsonField) = apply { + this.secretAccessKey = secretAccessKey + } + + /** Optional AWS session token for temporary credentials */ + fun sessionToken(sessionToken: String) = sessionToken(JsonField.of(sessionToken)) + + /** + * Sets [Builder.sessionToken] to an arbitrary JSON value. + * + * You should usually call [Builder.sessionToken] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun sessionToken(sessionToken: JsonField) = apply { + this.sessionToken = sessionToken + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BedrockAwsCredentialsProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .accessKeyId() + * .region() + * .secretAccessKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BedrockAwsCredentialsProviderOptions = + BedrockAwsCredentialsProviderOptions( + checkRequired("accessKeyId", accessKeyId), + checkRequired("region", region), + checkRequired("secretAccessKey", secretAccessKey), + sessionToken, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BedrockAwsCredentialsProviderOptions = apply { + if (validated) { + return@apply + } + + accessKeyId() + region() + secretAccessKey() + sessionToken() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (accessKeyId.asKnown().isPresent) 1 else 0) + + (if (region.asKnown().isPresent) 1 else 0) + + (if (secretAccessKey.asKnown().isPresent) 1 else 0) + + (if (sessionToken.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BedrockAwsCredentialsProviderOptions && + accessKeyId == other.accessKeyId && + region == other.region && + secretAccessKey == other.secretAccessKey && + sessionToken == other.sessionToken && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + accessKeyId, + region, + secretAccessKey, + sessionToken, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BedrockAwsCredentialsProviderOptions{accessKeyId=$accessKeyId, region=$region, secretAccessKey=$secretAccessKey, sessionToken=$sessionToken, additionalProperties=$additionalProperties}" + } + + class GoogleVertexProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val googleAuthOptions: JsonField, + private val headers: JsonField, + private val location: JsonField, + private val project: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("googleAuthOptions") + @ExcludeMissing + googleAuthOptions: JsonField = JsonMissing.of(), + @JsonProperty("headers") + @ExcludeMissing + headers: JsonField = JsonMissing.of(), + @JsonProperty("location") + @ExcludeMissing + location: JsonField = JsonMissing.of(), + @JsonProperty("project") + @ExcludeMissing + project: JsonField = JsonMissing.of(), + ) : this(googleAuthOptions, headers, location, project, mutableMapOf()) + + /** + * Optional Google auth options for Vertex AI + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun googleAuthOptions(): Optional = + googleAuthOptions.getOptional("googleAuthOptions") + + /** + * Custom headers for Vertex AI requests + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun headers(): Optional = headers.getOptional("headers") + + /** + * Google Cloud location for Vertex AI + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun location(): Optional = location.getOptional("location") + + /** + * Google Cloud project ID for Vertex AI + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun project(): Optional = project.getOptional("project") + + /** + * Returns the raw JSON value of [googleAuthOptions]. + * + * Unlike [googleAuthOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("googleAuthOptions") + @ExcludeMissing + fun _googleAuthOptions(): JsonField = googleAuthOptions + + /** + * Returns the raw JSON value of [headers]. + * + * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers + + /** + * Returns the raw JSON value of [location]. + * + * Unlike [location], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("location") @ExcludeMissing fun _location(): JsonField = location + + /** + * Returns the raw JSON value of [project]. + * + * Unlike [project], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("project") @ExcludeMissing fun _project(): JsonField = project + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GoogleVertexProviderOptions]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GoogleVertexProviderOptions]. */ + class Builder internal constructor() { + + private var googleAuthOptions: JsonField = JsonMissing.of() + private var headers: JsonField = JsonMissing.of() + private var location: JsonField = JsonMissing.of() + private var project: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(googleVertexProviderOptions: GoogleVertexProviderOptions) = + apply { + googleAuthOptions = googleVertexProviderOptions.googleAuthOptions + headers = googleVertexProviderOptions.headers + location = googleVertexProviderOptions.location + project = googleVertexProviderOptions.project + additionalProperties = + googleVertexProviderOptions.additionalProperties.toMutableMap() + } + + /** Optional Google auth options for Vertex AI */ + fun googleAuthOptions(googleAuthOptions: GoogleAuthOptions) = + googleAuthOptions(JsonField.of(googleAuthOptions)) + + /** + * Sets [Builder.googleAuthOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.googleAuthOptions] with a well-typed + * [GoogleAuthOptions] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun googleAuthOptions(googleAuthOptions: JsonField) = apply { + this.googleAuthOptions = googleAuthOptions + } + + /** Custom headers for Vertex AI requests */ + fun headers(headers: Headers) = headers(JsonField.of(headers)) + + /** + * Sets [Builder.headers] to an arbitrary JSON value. + * + * You should usually call [Builder.headers] with a well-typed [Headers] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun headers(headers: JsonField) = apply { this.headers = headers } + + /** Google Cloud location for Vertex AI */ + fun location(location: String) = location(JsonField.of(location)) + + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun location(location: JsonField) = apply { this.location = location } + + /** Google Cloud project ID for Vertex AI */ + fun project(project: String) = project(JsonField.of(project)) + + /** + * Sets [Builder.project] to an arbitrary JSON value. + * + * You should usually call [Builder.project] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun project(project: JsonField) = apply { this.project = project } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GoogleVertexProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GoogleVertexProviderOptions = + GoogleVertexProviderOptions( + googleAuthOptions, + headers, + location, + project, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GoogleVertexProviderOptions = apply { + if (validated) { + return@apply + } + + googleAuthOptions().ifPresent { it.validate() } + headers().ifPresent { it.validate() } + location() + project() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (googleAuthOptions.asKnown().getOrNull()?.validity() ?: 0) + + (headers.asKnown().getOrNull()?.validity() ?: 0) + + (if (location.asKnown().isPresent) 1 else 0) + + (if (project.asKnown().isPresent) 1 else 0) + + /** Optional Google auth options for Vertex AI */ + class GoogleAuthOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val credentials: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("credentials") + @ExcludeMissing + credentials: JsonField = JsonMissing.of() + ) : this(credentials, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun credentials(): Optional = credentials.getOptional("credentials") + + /** + * Returns the raw JSON value of [credentials]. + * + * Unlike [credentials], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credentials") + @ExcludeMissing + fun _credentials(): JsonField = credentials + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GoogleAuthOptions]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GoogleAuthOptions]. */ + class Builder internal constructor() { + + private var credentials: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(googleAuthOptions: GoogleAuthOptions) = apply { + credentials = googleAuthOptions.credentials + additionalProperties = googleAuthOptions.additionalProperties.toMutableMap() + } + + fun credentials(credentials: Credentials) = + credentials(JsonField.of(credentials)) + + /** + * Sets [Builder.credentials] to an arbitrary JSON value. + * + * You should usually call [Builder.credentials] with a well-typed [Credentials] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun credentials(credentials: JsonField) = apply { + this.credentials = credentials + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GoogleAuthOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GoogleAuthOptions = + GoogleAuthOptions(credentials, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): GoogleAuthOptions = apply { + if (validated) { + return@apply + } + + credentials().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (credentials.asKnown().getOrNull()?.validity() ?: 0) + + class Credentials + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val authProviderX509CertUrl: JsonField, + private val authUri: JsonField, + private val clientEmail: JsonField, + private val clientId: JsonField, + private val clientX509CertUrl: JsonField, + private val privateKey: JsonField, + private val privateKeyId: JsonField, + private val projectId: JsonField, + private val tokenUri: JsonField, + private val type: JsonField, + private val universeDomain: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("auth_provider_x509_cert_url") + @ExcludeMissing + authProviderX509CertUrl: JsonField = JsonMissing.of(), + @JsonProperty("auth_uri") + @ExcludeMissing + authUri: JsonField = JsonMissing.of(), + @JsonProperty("client_email") + @ExcludeMissing + clientEmail: JsonField = JsonMissing.of(), + @JsonProperty("client_id") + @ExcludeMissing + clientId: JsonField = JsonMissing.of(), + @JsonProperty("client_x509_cert_url") + @ExcludeMissing + clientX509CertUrl: JsonField = JsonMissing.of(), + @JsonProperty("private_key") + @ExcludeMissing + privateKey: JsonField = JsonMissing.of(), + @JsonProperty("private_key_id") + @ExcludeMissing + privateKeyId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("token_uri") + @ExcludeMissing + tokenUri: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("universe_domain") + @ExcludeMissing + universeDomain: JsonField = JsonMissing.of(), + ) : this( + authProviderX509CertUrl, + authUri, + clientEmail, + clientId, + clientX509CertUrl, + privateKey, + privateKeyId, + projectId, + tokenUri, + type, + universeDomain, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun authProviderX509CertUrl(): Optional = + authProviderX509CertUrl.getOptional("auth_provider_x509_cert_url") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun authUri(): Optional = authUri.getOptional("auth_uri") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun clientEmail(): Optional = clientEmail.getOptional("client_email") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun clientId(): Optional = clientId.getOptional("client_id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun clientX509CertUrl(): Optional = + clientX509CertUrl.getOptional("client_x509_cert_url") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun privateKey(): Optional = privateKey.getOptional("private_key") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun privateKeyId(): Optional = + privateKeyId.getOptional("private_key_id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun projectId(): Optional = projectId.getOptional("project_id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun tokenUri(): Optional = tokenUri.getOptional("token_uri") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun universeDomain(): Optional = + universeDomain.getOptional("universe_domain") + + /** + * Returns the raw JSON value of [authProviderX509CertUrl]. + * + * Unlike [authProviderX509CertUrl], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("auth_provider_x509_cert_url") + @ExcludeMissing + fun _authProviderX509CertUrl(): JsonField = authProviderX509CertUrl + + /** + * Returns the raw JSON value of [authUri]. + * + * Unlike [authUri], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("auth_uri") + @ExcludeMissing + fun _authUri(): JsonField = authUri + + /** + * Returns the raw JSON value of [clientEmail]. + * + * Unlike [clientEmail], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("client_email") + @ExcludeMissing + fun _clientEmail(): JsonField = clientEmail + + /** + * Returns the raw JSON value of [clientId]. + * + * Unlike [clientId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("client_id") + @ExcludeMissing + fun _clientId(): JsonField = clientId + + /** + * Returns the raw JSON value of [clientX509CertUrl]. + * + * Unlike [clientX509CertUrl], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("client_x509_cert_url") + @ExcludeMissing + fun _clientX509CertUrl(): JsonField = clientX509CertUrl + + /** + * Returns the raw JSON value of [privateKey]. + * + * Unlike [privateKey], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("private_key") + @ExcludeMissing + fun _privateKey(): JsonField = privateKey + + /** + * Returns the raw JSON value of [privateKeyId]. + * + * Unlike [privateKeyId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("private_key_id") + @ExcludeMissing + fun _privateKeyId(): JsonField = privateKeyId + + /** + * Returns the raw JSON value of [projectId]. + * + * Unlike [projectId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("project_id") + @ExcludeMissing + fun _projectId(): JsonField = projectId + + /** + * Returns the raw JSON value of [tokenUri]. + * + * Unlike [tokenUri], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("token_uri") + @ExcludeMissing + fun _tokenUri(): JsonField = tokenUri + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [universeDomain]. + * + * Unlike [universeDomain], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("universe_domain") + @ExcludeMissing + fun _universeDomain(): JsonField = universeDomain + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Credentials]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Credentials]. */ + class Builder internal constructor() { + + private var authProviderX509CertUrl: JsonField = JsonMissing.of() + private var authUri: JsonField = JsonMissing.of() + private var clientEmail: JsonField = JsonMissing.of() + private var clientId: JsonField = JsonMissing.of() + private var clientX509CertUrl: JsonField = JsonMissing.of() + private var privateKey: JsonField = JsonMissing.of() + private var privateKeyId: JsonField = JsonMissing.of() + private var projectId: JsonField = JsonMissing.of() + private var tokenUri: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var universeDomain: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(credentials: Credentials) = apply { + authProviderX509CertUrl = credentials.authProviderX509CertUrl + authUri = credentials.authUri + clientEmail = credentials.clientEmail + clientId = credentials.clientId + clientX509CertUrl = credentials.clientX509CertUrl + privateKey = credentials.privateKey + privateKeyId = credentials.privateKeyId + projectId = credentials.projectId + tokenUri = credentials.tokenUri + type = credentials.type + universeDomain = credentials.universeDomain + additionalProperties = credentials.additionalProperties.toMutableMap() + } + + fun authProviderX509CertUrl(authProviderX509CertUrl: String) = + authProviderX509CertUrl(JsonField.of(authProviderX509CertUrl)) + + /** + * Sets [Builder.authProviderX509CertUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.authProviderX509CertUrl] with a + * well-typed [String] value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun authProviderX509CertUrl(authProviderX509CertUrl: JsonField) = + apply { + this.authProviderX509CertUrl = authProviderX509CertUrl + } + + fun authUri(authUri: String) = authUri(JsonField.of(authUri)) + + /** + * Sets [Builder.authUri] to an arbitrary JSON value. + * + * You should usually call [Builder.authUri] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun authUri(authUri: JsonField) = apply { this.authUri = authUri } + + fun clientEmail(clientEmail: String) = + clientEmail(JsonField.of(clientEmail)) + + /** + * Sets [Builder.clientEmail] to an arbitrary JSON value. + * + * You should usually call [Builder.clientEmail] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun clientEmail(clientEmail: JsonField) = apply { + this.clientEmail = clientEmail + } + + fun clientId(clientId: String) = clientId(JsonField.of(clientId)) + + /** + * Sets [Builder.clientId] to an arbitrary JSON value. + * + * You should usually call [Builder.clientId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun clientId(clientId: JsonField) = apply { + this.clientId = clientId + } + + fun clientX509CertUrl(clientX509CertUrl: String) = + clientX509CertUrl(JsonField.of(clientX509CertUrl)) + + /** + * Sets [Builder.clientX509CertUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.clientX509CertUrl] with a well-typed + * [String] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun clientX509CertUrl(clientX509CertUrl: JsonField) = apply { + this.clientX509CertUrl = clientX509CertUrl + } + + fun privateKey(privateKey: String) = privateKey(JsonField.of(privateKey)) + + /** + * Sets [Builder.privateKey] to an arbitrary JSON value. + * + * You should usually call [Builder.privateKey] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun privateKey(privateKey: JsonField) = apply { + this.privateKey = privateKey + } + + fun privateKeyId(privateKeyId: String) = + privateKeyId(JsonField.of(privateKeyId)) + + /** + * Sets [Builder.privateKeyId] to an arbitrary JSON value. + * + * You should usually call [Builder.privateKeyId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun privateKeyId(privateKeyId: JsonField) = apply { + this.privateKeyId = privateKeyId + } + + fun projectId(projectId: String) = projectId(JsonField.of(projectId)) + + /** + * Sets [Builder.projectId] to an arbitrary JSON value. + * + * You should usually call [Builder.projectId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun projectId(projectId: JsonField) = apply { + this.projectId = projectId + } + + fun tokenUri(tokenUri: String) = tokenUri(JsonField.of(tokenUri)) + + /** + * Sets [Builder.tokenUri] to an arbitrary JSON value. + * + * You should usually call [Builder.tokenUri] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun tokenUri(tokenUri: JsonField) = apply { + this.tokenUri = tokenUri + } + + fun type(type: String) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun universeDomain(universeDomain: String) = + universeDomain(JsonField.of(universeDomain)) + + /** + * Sets [Builder.universeDomain] to an arbitrary JSON value. + * + * You should usually call [Builder.universeDomain] with a well-typed + * [String] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun universeDomain(universeDomain: JsonField) = apply { + this.universeDomain = universeDomain + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Credentials]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Credentials = + Credentials( + authProviderX509CertUrl, + authUri, + clientEmail, + clientId, + clientX509CertUrl, + privateKey, + privateKeyId, + projectId, + tokenUri, + type, + universeDomain, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Credentials = apply { + if (validated) { + return@apply + } + + authProviderX509CertUrl() + authUri() + clientEmail() + clientId() + clientX509CertUrl() + privateKey() + privateKeyId() + projectId() + tokenUri() + type() + universeDomain() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (authProviderX509CertUrl.asKnown().isPresent) 1 else 0) + + (if (authUri.asKnown().isPresent) 1 else 0) + + (if (clientEmail.asKnown().isPresent) 1 else 0) + + (if (clientId.asKnown().isPresent) 1 else 0) + + (if (clientX509CertUrl.asKnown().isPresent) 1 else 0) + + (if (privateKey.asKnown().isPresent) 1 else 0) + + (if (privateKeyId.asKnown().isPresent) 1 else 0) + + (if (projectId.asKnown().isPresent) 1 else 0) + + (if (tokenUri.asKnown().isPresent) 1 else 0) + + (if (type.asKnown().isPresent) 1 else 0) + + (if (universeDomain.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Credentials && + authProviderX509CertUrl == other.authProviderX509CertUrl && + authUri == other.authUri && + clientEmail == other.clientEmail && + clientId == other.clientId && + clientX509CertUrl == other.clientX509CertUrl && + privateKey == other.privateKey && + privateKeyId == other.privateKeyId && + projectId == other.projectId && + tokenUri == other.tokenUri && + type == other.type && + universeDomain == other.universeDomain && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + authProviderX509CertUrl, + authUri, + clientEmail, + clientId, + clientX509CertUrl, + privateKey, + privateKeyId, + projectId, + tokenUri, + type, + universeDomain, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Credentials{authProviderX509CertUrl=$authProviderX509CertUrl, authUri=$authUri, clientEmail=$clientEmail, clientId=$clientId, clientX509CertUrl=$clientX509CertUrl, privateKey=$privateKey, privateKeyId=$privateKeyId, projectId=$projectId, tokenUri=$tokenUri, type=$type, universeDomain=$universeDomain, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GoogleAuthOptions && + credentials == other.credentials && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(credentials, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GoogleAuthOptions{credentials=$credentials, additionalProperties=$additionalProperties}" + } + + /** Custom headers for Vertex AI requests */ + class Headers + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Headers]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Headers]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(headers: Headers) = apply { + additionalProperties = headers.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Headers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Headers = Headers(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Headers = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Headers{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GoogleVertexProviderOptions && + googleAuthOptions == other.googleAuthOptions && + headers == other.headers && + location == other.location && + project == other.project && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(googleAuthOptions, headers, location, project, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GoogleVertexProviderOptions{googleAuthOptions=$googleAuthOptions, headers=$headers, location=$location, project=$project, additionalProperties=$additionalProperties}" + } + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -551,15 +2513,26 @@ private constructor( baseUrl == other.baseUrl && headers == other.headers && provider == other.provider && + providerOptions == other.providerOptions && + skipApiKeyFallback == other.skipApiKeyFallback && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(modelName, apiKey, baseUrl, headers, provider, additionalProperties) + Objects.hash( + modelName, + apiKey, + baseUrl, + headers, + provider, + providerOptions, + skipApiKeyFallback, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, provider=$provider, additionalProperties=$additionalProperties}" + "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, provider=$provider, providerOptions=$providerOptions, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index f68232a..65fd5a6 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -1686,8 +1686,6 @@ private constructor( private val instruction: JsonField, private val highlightCursor: JsonField, private val maxSteps: JsonField, - private val toolTimeout: JsonField, - private val useSearch: JsonField, private val additionalProperties: MutableMap, ) { @@ -1699,16 +1697,8 @@ private constructor( @JsonProperty("highlightCursor") @ExcludeMissing highlightCursor: JsonField = JsonMissing.of(), - @JsonProperty("maxSteps") - @ExcludeMissing - maxSteps: JsonField = JsonMissing.of(), - @JsonProperty("toolTimeout") - @ExcludeMissing - toolTimeout: JsonField = JsonMissing.of(), - @JsonProperty("useSearch") - @ExcludeMissing - useSearch: JsonField = JsonMissing.of(), - ) : this(instruction, highlightCursor, maxSteps, toolTimeout, useSearch, mutableMapOf()) + @JsonProperty("maxSteps") @ExcludeMissing maxSteps: JsonField = JsonMissing.of(), + ) : this(instruction, highlightCursor, maxSteps, mutableMapOf()) /** * Natural language instruction for the agent @@ -1734,22 +1724,6 @@ private constructor( */ fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") - /** - * Timeout in milliseconds for each agent tool call - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun toolTimeout(): Optional = toolTimeout.getOptional("toolTimeout") - - /** - * Whether to enable the web search tool powered by Browserbase Search API - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun useSearch(): Optional = useSearch.getOptional("useSearch") - /** * Returns the raw JSON value of [instruction]. * @@ -1776,22 +1750,6 @@ private constructor( */ @JsonProperty("maxSteps") @ExcludeMissing fun _maxSteps(): JsonField = maxSteps - /** - * Returns the raw JSON value of [toolTimeout]. - * - * Unlike [toolTimeout], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("toolTimeout") - @ExcludeMissing - fun _toolTimeout(): JsonField = toolTimeout - - /** - * Returns the raw JSON value of [useSearch]. - * - * Unlike [useSearch], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("useSearch") @ExcludeMissing fun _useSearch(): JsonField = useSearch - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1823,8 +1781,6 @@ private constructor( private var instruction: JsonField? = null private var highlightCursor: JsonField = JsonMissing.of() private var maxSteps: JsonField = JsonMissing.of() - private var toolTimeout: JsonField = JsonMissing.of() - private var useSearch: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -1832,8 +1788,6 @@ private constructor( instruction = executeOptions.instruction highlightCursor = executeOptions.highlightCursor maxSteps = executeOptions.maxSteps - toolTimeout = executeOptions.toolTimeout - useSearch = executeOptions.useSearch additionalProperties = executeOptions.additionalProperties.toMutableMap() } @@ -1878,32 +1832,6 @@ private constructor( */ fun maxSteps(maxSteps: JsonField) = apply { this.maxSteps = maxSteps } - /** Timeout in milliseconds for each agent tool call */ - fun toolTimeout(toolTimeout: Double) = toolTimeout(JsonField.of(toolTimeout)) - - /** - * Sets [Builder.toolTimeout] to an arbitrary JSON value. - * - * You should usually call [Builder.toolTimeout] with a well-typed [Double] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun toolTimeout(toolTimeout: JsonField) = apply { - this.toolTimeout = toolTimeout - } - - /** Whether to enable the web search tool powered by Browserbase Search API */ - fun useSearch(useSearch: Boolean) = useSearch(JsonField.of(useSearch)) - - /** - * Sets [Builder.useSearch] to an arbitrary JSON value. - * - * You should usually call [Builder.useSearch] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun useSearch(useSearch: JsonField) = apply { this.useSearch = useSearch } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1940,8 +1868,6 @@ private constructor( checkRequired("instruction", instruction), highlightCursor, maxSteps, - toolTimeout, - useSearch, additionalProperties.toMutableMap(), ) } @@ -1956,8 +1882,6 @@ private constructor( instruction() highlightCursor() maxSteps() - toolTimeout() - useSearch() validated = true } @@ -1979,9 +1903,7 @@ private constructor( internal fun validity(): Int = (if (instruction.asKnown().isPresent) 1 else 0) + (if (highlightCursor.asKnown().isPresent) 1 else 0) + - (if (maxSteps.asKnown().isPresent) 1 else 0) + - (if (toolTimeout.asKnown().isPresent) 1 else 0) + - (if (useSearch.asKnown().isPresent) 1 else 0) + (if (maxSteps.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -1992,26 +1914,17 @@ private constructor( instruction == other.instruction && highlightCursor == other.highlightCursor && maxSteps == other.maxSteps && - toolTimeout == other.toolTimeout && - useSearch == other.useSearch && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash( - instruction, - highlightCursor, - maxSteps, - toolTimeout, - useSearch, - additionalProperties, - ) + Objects.hash(instruction, highlightCursor, maxSteps, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, toolTimeout=$toolTimeout, useSearch=$useSearch, additionalProperties=$additionalProperties}" + "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" } /** Whether to stream the response via SSE */ diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 5e09071..3b2547c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -100,6 +100,15 @@ private constructor( */ fun experimental(): Optional = body.experimental() + /** + * Optional provider-specific configuration for the session model (for example Bedrock region + * and credentials) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun modelClientOptions(): Optional = body.modelClientOptions() + /** * Enable self-healing for failed actions * @@ -185,6 +194,14 @@ private constructor( */ fun _experimental(): JsonField = body._experimental() + /** + * Returns the raw JSON value of [modelClientOptions]. + * + * Unlike [modelClientOptions], this method doesn't throw if the JSON field has an unexpected + * type. + */ + fun _modelClientOptions(): JsonField = body._modelClientOptions() + /** * Returns the raw JSON value of [selfHeal]. * @@ -372,6 +389,47 @@ private constructor( body.experimental(experimental) } + /** + * Optional provider-specific configuration for the session model (for example Bedrock + * region and credentials) + */ + fun modelClientOptions(modelClientOptions: ModelClientOptions) = apply { + body.modelClientOptions(modelClientOptions) + } + + /** + * Sets [Builder.modelClientOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.modelClientOptions] with a well-typed + * [ModelClientOptions] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun modelClientOptions(modelClientOptions: JsonField) = apply { + body.modelClientOptions(modelClientOptions) + } + + /** + * Alias for calling [modelClientOptions] with + * `ModelClientOptions.ofBedrockApiKey(bedrockApiKey)`. + */ + fun modelClientOptions(bedrockApiKey: ModelClientOptions.BedrockApiKeyModelClientOptions) = + apply { + body.modelClientOptions(bedrockApiKey) + } + + /** + * Alias for calling [modelClientOptions] with + * `ModelClientOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. + */ + fun modelClientOptions( + bedrockAwsCredentials: ModelClientOptions.BedrockAwsCredentialsModelClientOptions + ) = apply { body.modelClientOptions(bedrockAwsCredentials) } + + /** Alias for calling [modelClientOptions] with `ModelClientOptions.ofGeneric(generic)`. */ + fun modelClientOptions(generic: ModelClientOptions.GenericModelClientOptions) = apply { + body.modelClientOptions(generic) + } + /** Enable self-healing for failed actions */ fun selfHeal(selfHeal: Boolean) = apply { body.selfHeal(selfHeal) } @@ -585,6 +643,7 @@ private constructor( private val browserbaseSessionId: JsonField, private val domSettleTimeoutMs: JsonField, private val experimental: JsonField, + private val modelClientOptions: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, private val verbose: JsonField, @@ -614,6 +673,9 @@ private constructor( @JsonProperty("experimental") @ExcludeMissing experimental: JsonField = JsonMissing.of(), + @JsonProperty("modelClientOptions") + @ExcludeMissing + modelClientOptions: JsonField = JsonMissing.of(), @JsonProperty("selfHeal") @ExcludeMissing selfHeal: JsonField = JsonMissing.of(), @@ -632,6 +694,7 @@ private constructor( browserbaseSessionId, domSettleTimeoutMs, experimental, + modelClientOptions, selfHeal, systemPrompt, verbose, @@ -692,6 +755,16 @@ private constructor( */ fun experimental(): Optional = experimental.getOptional("experimental") + /** + * Optional provider-specific configuration for the session model (for example Bedrock + * region and credentials) + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun modelClientOptions(): Optional = + modelClientOptions.getOptional("modelClientOptions") + /** * Enable self-healing for failed actions * @@ -790,6 +863,16 @@ private constructor( @ExcludeMissing fun _experimental(): JsonField = experimental + /** + * Returns the raw JSON value of [modelClientOptions]. + * + * Unlike [modelClientOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("modelClientOptions") + @ExcludeMissing + fun _modelClientOptions(): JsonField = modelClientOptions + /** * Returns the raw JSON value of [selfHeal]. * @@ -860,6 +943,7 @@ private constructor( private var browserbaseSessionId: JsonField = JsonMissing.of() private var domSettleTimeoutMs: JsonField = JsonMissing.of() private var experimental: JsonField = JsonMissing.of() + private var modelClientOptions: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() private var verbose: JsonField = JsonMissing.of() @@ -875,6 +959,7 @@ private constructor( browserbaseSessionId = body.browserbaseSessionId domSettleTimeoutMs = body.domSettleTimeoutMs experimental = body.experimental + modelClientOptions = body.modelClientOptions selfHeal = body.selfHeal systemPrompt = body.systemPrompt verbose = body.verbose @@ -977,6 +1062,49 @@ private constructor( this.experimental = experimental } + /** + * Optional provider-specific configuration for the session model (for example Bedrock + * region and credentials) + */ + fun modelClientOptions(modelClientOptions: ModelClientOptions) = + modelClientOptions(JsonField.of(modelClientOptions)) + + /** + * Sets [Builder.modelClientOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.modelClientOptions] with a well-typed + * [ModelClientOptions] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun modelClientOptions(modelClientOptions: JsonField) = apply { + this.modelClientOptions = modelClientOptions + } + + /** + * Alias for calling [modelClientOptions] with + * `ModelClientOptions.ofBedrockApiKey(bedrockApiKey)`. + */ + fun modelClientOptions( + bedrockApiKey: ModelClientOptions.BedrockApiKeyModelClientOptions + ) = modelClientOptions(ModelClientOptions.ofBedrockApiKey(bedrockApiKey)) + + /** + * Alias for calling [modelClientOptions] with + * `ModelClientOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. + */ + fun modelClientOptions( + bedrockAwsCredentials: ModelClientOptions.BedrockAwsCredentialsModelClientOptions + ) = + modelClientOptions( + ModelClientOptions.ofBedrockAwsCredentials(bedrockAwsCredentials) + ) + + /** + * Alias for calling [modelClientOptions] with `ModelClientOptions.ofGeneric(generic)`. + */ + fun modelClientOptions(generic: ModelClientOptions.GenericModelClientOptions) = + modelClientOptions(ModelClientOptions.ofGeneric(generic)) + /** Enable self-healing for failed actions */ fun selfHeal(selfHeal: Boolean) = selfHeal(JsonField.of(selfHeal)) @@ -1070,6 +1198,7 @@ private constructor( browserbaseSessionId, domSettleTimeoutMs, experimental, + modelClientOptions, selfHeal, systemPrompt, verbose, @@ -1092,6 +1221,7 @@ private constructor( browserbaseSessionId() domSettleTimeoutMs() experimental() + modelClientOptions().ifPresent { it.validate() } selfHeal() systemPrompt() verbose().ifPresent { it.validate() } @@ -1122,6 +1252,7 @@ private constructor( (if (browserbaseSessionId.asKnown().isPresent) 1 else 0) + (if (domSettleTimeoutMs.asKnown().isPresent) 1 else 0) + (if (experimental.asKnown().isPresent) 1 else 0) + + (modelClientOptions.asKnown().getOrNull()?.validity() ?: 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + (verbose.asKnown().getOrNull()?.validity() ?: 0) + @@ -1140,6 +1271,7 @@ private constructor( browserbaseSessionId == other.browserbaseSessionId && domSettleTimeoutMs == other.domSettleTimeoutMs && experimental == other.experimental && + modelClientOptions == other.modelClientOptions && selfHeal == other.selfHeal && systemPrompt == other.systemPrompt && verbose == other.verbose && @@ -1156,6 +1288,7 @@ private constructor( browserbaseSessionId, domSettleTimeoutMs, experimental, + modelClientOptions, selfHeal, systemPrompt, verbose, @@ -1167,7 +1300,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" + "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, modelClientOptions=$modelClientOptions, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" } class Browser @@ -7195,6 +7328,3960 @@ private constructor( "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" } + /** + * Optional provider-specific configuration for the session model (for example Bedrock region + * and credentials) + */ + @JsonDeserialize(using = ModelClientOptions.Deserializer::class) + @JsonSerialize(using = ModelClientOptions.Serializer::class) + class ModelClientOptions + private constructor( + private val bedrockApiKey: BedrockApiKeyModelClientOptions? = null, + private val bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions? = null, + private val generic: GenericModelClientOptions? = null, + private val _json: JsonValue? = null, + ) { + + fun bedrockApiKey(): Optional = + Optional.ofNullable(bedrockApiKey) + + fun bedrockAwsCredentials(): Optional = + Optional.ofNullable(bedrockAwsCredentials) + + fun generic(): Optional = Optional.ofNullable(generic) + + fun isBedrockApiKey(): Boolean = bedrockApiKey != null + + fun isBedrockAwsCredentials(): Boolean = bedrockAwsCredentials != null + + fun isGeneric(): Boolean = generic != null + + fun asBedrockApiKey(): BedrockApiKeyModelClientOptions = + bedrockApiKey.getOrThrow("bedrockApiKey") + + fun asBedrockAwsCredentials(): BedrockAwsCredentialsModelClientOptions = + bedrockAwsCredentials.getOrThrow("bedrockAwsCredentials") + + fun asGeneric(): GenericModelClientOptions = generic.getOrThrow("generic") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + bedrockApiKey != null -> visitor.visitBedrockApiKey(bedrockApiKey) + bedrockAwsCredentials != null -> + visitor.visitBedrockAwsCredentials(bedrockAwsCredentials) + generic != null -> visitor.visitGeneric(generic) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ModelClientOptions = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitBedrockApiKey( + bedrockApiKey: BedrockApiKeyModelClientOptions + ) { + bedrockApiKey.validate() + } + + override fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions + ) { + bedrockAwsCredentials.validate() + } + + override fun visitGeneric(generic: GenericModelClientOptions) { + generic.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBedrockApiKey( + bedrockApiKey: BedrockApiKeyModelClientOptions + ) = bedrockApiKey.validity() + + override fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions + ) = bedrockAwsCredentials.validity() + + override fun visitGeneric(generic: GenericModelClientOptions) = + generic.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ModelClientOptions && + bedrockApiKey == other.bedrockApiKey && + bedrockAwsCredentials == other.bedrockAwsCredentials && + generic == other.generic + } + + override fun hashCode(): Int = Objects.hash(bedrockApiKey, bedrockAwsCredentials, generic) + + override fun toString(): String = + when { + bedrockApiKey != null -> "ModelClientOptions{bedrockApiKey=$bedrockApiKey}" + bedrockAwsCredentials != null -> + "ModelClientOptions{bedrockAwsCredentials=$bedrockAwsCredentials}" + generic != null -> "ModelClientOptions{generic=$generic}" + _json != null -> "ModelClientOptions{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ModelClientOptions") + } + + companion object { + + @JvmStatic + fun ofBedrockApiKey(bedrockApiKey: BedrockApiKeyModelClientOptions) = + ModelClientOptions(bedrockApiKey = bedrockApiKey) + + @JvmStatic + fun ofBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions + ) = ModelClientOptions(bedrockAwsCredentials = bedrockAwsCredentials) + + @JvmStatic + fun ofGeneric(generic: GenericModelClientOptions) = + ModelClientOptions(generic = generic) + } + + /** + * An interface that defines how to map each variant of [ModelClientOptions] to a value of + * type [T]. + */ + interface Visitor { + + fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyModelClientOptions): T + + fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions + ): T + + fun visitGeneric(generic: GenericModelClientOptions): T + + /** + * Maps an unknown variant of [ModelClientOptions] to a value of type [T]. + * + * An instance of [ModelClientOptions] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown ModelClientOptions: $json") + } + } + + internal class Deserializer : + BaseDeserializer(ModelClientOptions::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ModelClientOptions { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { ModelClientOptions(bedrockApiKey = it, _json = json) }, + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { + ModelClientOptions(bedrockAwsCredentials = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ModelClientOptions(generic = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> ModelClientOptions(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(ModelClientOptions::class) { + + override fun serialize( + value: ModelClientOptions, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.bedrockApiKey != null -> generator.writeObject(value.bedrockApiKey) + value.bedrockAwsCredentials != null -> + generator.writeObject(value.bedrockAwsCredentials) + value.generic != null -> generator.writeObject(value.generic) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ModelClientOptions") + } + } + } + + class BedrockApiKeyModelClientOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val apiKey: JsonField, + private val providerOptions: JsonField, + private val baseUrl: JsonField, + private val headers: JsonField, + private val skipApiKeyFallback: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("apiKey") + @ExcludeMissing + apiKey: JsonField = JsonMissing.of(), + @JsonProperty("providerOptions") + @ExcludeMissing + providerOptions: JsonField = JsonMissing.of(), + @JsonProperty("baseURL") + @ExcludeMissing + baseUrl: JsonField = JsonMissing.of(), + @JsonProperty("headers") + @ExcludeMissing + headers: JsonField = JsonMissing.of(), + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + skipApiKeyFallback: JsonField = JsonMissing.of(), + ) : this(apiKey, providerOptions, baseUrl, headers, skipApiKeyFallback, mutableMapOf()) + + /** + * Short-term Bedrock API key for bearer-token auth + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun apiKey(): String = apiKey.getRequired("apiKey") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun providerOptions(): ProviderOptions = providerOptions.getRequired("providerOptions") + + /** + * Base URL for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + + /** + * Custom headers for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun headers(): Optional = headers.getOptional("headers") + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this + * when auth is carried through providerOptions instead of an API key. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun skipApiKeyFallback(): Optional = + skipApiKeyFallback.getOptional("skipApiKeyFallback") + + /** + * Returns the raw JSON value of [apiKey]. + * + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + + /** + * Returns the raw JSON value of [providerOptions]. + * + * Unlike [providerOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("providerOptions") + @ExcludeMissing + fun _providerOptions(): JsonField = providerOptions + + /** + * Returns the raw JSON value of [baseUrl]. + * + * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + + /** + * Returns the raw JSON value of [headers]. + * + * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers + + /** + * Returns the raw JSON value of [skipApiKeyFallback]. + * + * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BedrockApiKeyModelClientOptions]. + * + * The following fields are required: + * ```java + * .apiKey() + * .providerOptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BedrockApiKeyModelClientOptions]. */ + class Builder internal constructor() { + + private var apiKey: JsonField? = null + private var providerOptions: JsonField? = null + private var baseUrl: JsonField = JsonMissing.of() + private var headers: JsonField = JsonMissing.of() + private var skipApiKeyFallback: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from( + bedrockApiKeyModelClientOptions: BedrockApiKeyModelClientOptions + ) = apply { + apiKey = bedrockApiKeyModelClientOptions.apiKey + providerOptions = bedrockApiKeyModelClientOptions.providerOptions + baseUrl = bedrockApiKeyModelClientOptions.baseUrl + headers = bedrockApiKeyModelClientOptions.headers + skipApiKeyFallback = bedrockApiKeyModelClientOptions.skipApiKeyFallback + additionalProperties = + bedrockApiKeyModelClientOptions.additionalProperties.toMutableMap() + } + + /** Short-term Bedrock API key for bearer-token auth */ + fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + + /** + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + + fun providerOptions(providerOptions: ProviderOptions) = + providerOptions(JsonField.of(providerOptions)) + + /** + * Sets [Builder.providerOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.providerOptions] with a well-typed + * [ProviderOptions] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun providerOptions(providerOptions: JsonField) = apply { + this.providerOptions = providerOptions + } + + /** Base URL for the model provider */ + fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) + + /** + * Sets [Builder.baseUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.baseUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + + /** Custom headers for the model provider */ + fun headers(headers: Headers) = headers(JsonField.of(headers)) + + /** + * Sets [Builder.headers] to an arbitrary JSON value. + * + * You should usually call [Builder.headers] with a well-typed [Headers] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun headers(headers: JsonField) = apply { this.headers = headers } + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use + * this when auth is carried through providerOptions instead of an API key. + */ + fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = + skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) + + /** + * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. + * + * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { + this.skipApiKeyFallback = skipApiKeyFallback + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BedrockApiKeyModelClientOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .apiKey() + * .providerOptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BedrockApiKeyModelClientOptions = + BedrockApiKeyModelClientOptions( + checkRequired("apiKey", apiKey), + checkRequired("providerOptions", providerOptions), + baseUrl, + headers, + skipApiKeyFallback, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BedrockApiKeyModelClientOptions = apply { + if (validated) { + return@apply + } + + apiKey() + providerOptions().validate() + baseUrl() + headers().ifPresent { it.validate() } + skipApiKeyFallback() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (apiKey.asKnown().isPresent) 1 else 0) + + (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (headers.asKnown().getOrNull()?.validity() ?: 0) + + (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) + + class ProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val region: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("region") + @ExcludeMissing + region: JsonField = JsonMissing.of() + ) : this(region, mutableMapOf()) + + /** + * AWS region for Amazon Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun region(): String = region.getRequired("region") + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ProviderOptions]. + * + * The following fields are required: + * ```java + * .region() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ProviderOptions]. */ + class Builder internal constructor() { + + private var region: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(providerOptions: ProviderOptions) = apply { + region = providerOptions.region + additionalProperties = providerOptions.additionalProperties.toMutableMap() + } + + /** AWS region for Amazon Bedrock */ + fun region(region: String) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .region() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProviderOptions = + ProviderOptions( + checkRequired("region", region), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProviderOptions = apply { + if (validated) { + return@apply + } + + region() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (if (region.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProviderOptions && + region == other.region && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(region, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProviderOptions{region=$region, additionalProperties=$additionalProperties}" + } + + /** Custom headers for the model provider */ + class Headers + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Headers]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Headers]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(headers: Headers) = apply { + additionalProperties = headers.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Headers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Headers = Headers(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Headers = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Headers{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BedrockApiKeyModelClientOptions && + apiKey == other.apiKey && + providerOptions == other.providerOptions && + baseUrl == other.baseUrl && + headers == other.headers && + skipApiKeyFallback == other.skipApiKeyFallback && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + apiKey, + providerOptions, + baseUrl, + headers, + skipApiKeyFallback, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BedrockApiKeyModelClientOptions{apiKey=$apiKey, providerOptions=$providerOptions, baseUrl=$baseUrl, headers=$headers, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" + } + + class BedrockAwsCredentialsModelClientOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val providerOptions: JsonField, + private val baseUrl: JsonField, + private val headers: JsonField, + private val skipApiKeyFallback: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("providerOptions") + @ExcludeMissing + providerOptions: JsonField = JsonMissing.of(), + @JsonProperty("baseURL") + @ExcludeMissing + baseUrl: JsonField = JsonMissing.of(), + @JsonProperty("headers") + @ExcludeMissing + headers: JsonField = JsonMissing.of(), + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + skipApiKeyFallback: JsonField = JsonMissing.of(), + ) : this(providerOptions, baseUrl, headers, skipApiKeyFallback, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun providerOptions(): ProviderOptions = providerOptions.getRequired("providerOptions") + + /** + * Base URL for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + + /** + * Custom headers for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun headers(): Optional = headers.getOptional("headers") + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this + * when auth is carried through providerOptions instead of an API key. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun skipApiKeyFallback(): Optional = + skipApiKeyFallback.getOptional("skipApiKeyFallback") + + /** + * Returns the raw JSON value of [providerOptions]. + * + * Unlike [providerOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("providerOptions") + @ExcludeMissing + fun _providerOptions(): JsonField = providerOptions + + /** + * Returns the raw JSON value of [baseUrl]. + * + * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + + /** + * Returns the raw JSON value of [headers]. + * + * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers + + /** + * Returns the raw JSON value of [skipApiKeyFallback]. + * + * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BedrockAwsCredentialsModelClientOptions]. + * + * The following fields are required: + * ```java + * .providerOptions() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BedrockAwsCredentialsModelClientOptions]. */ + class Builder internal constructor() { + + private var providerOptions: JsonField? = null + private var baseUrl: JsonField = JsonMissing.of() + private var headers: JsonField = JsonMissing.of() + private var skipApiKeyFallback: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from( + bedrockAwsCredentialsModelClientOptions: BedrockAwsCredentialsModelClientOptions + ) = apply { + providerOptions = bedrockAwsCredentialsModelClientOptions.providerOptions + baseUrl = bedrockAwsCredentialsModelClientOptions.baseUrl + headers = bedrockAwsCredentialsModelClientOptions.headers + skipApiKeyFallback = bedrockAwsCredentialsModelClientOptions.skipApiKeyFallback + additionalProperties = + bedrockAwsCredentialsModelClientOptions.additionalProperties.toMutableMap() + } + + fun providerOptions(providerOptions: ProviderOptions) = + providerOptions(JsonField.of(providerOptions)) + + /** + * Sets [Builder.providerOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.providerOptions] with a well-typed + * [ProviderOptions] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun providerOptions(providerOptions: JsonField) = apply { + this.providerOptions = providerOptions + } + + /** Base URL for the model provider */ + fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) + + /** + * Sets [Builder.baseUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.baseUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + + /** Custom headers for the model provider */ + fun headers(headers: Headers) = headers(JsonField.of(headers)) + + /** + * Sets [Builder.headers] to an arbitrary JSON value. + * + * You should usually call [Builder.headers] with a well-typed [Headers] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun headers(headers: JsonField) = apply { this.headers = headers } + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use + * this when auth is carried through providerOptions instead of an API key. + */ + fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = + skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) + + /** + * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. + * + * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { + this.skipApiKeyFallback = skipApiKeyFallback + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BedrockAwsCredentialsModelClientOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .providerOptions() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BedrockAwsCredentialsModelClientOptions = + BedrockAwsCredentialsModelClientOptions( + checkRequired("providerOptions", providerOptions), + baseUrl, + headers, + skipApiKeyFallback, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BedrockAwsCredentialsModelClientOptions = apply { + if (validated) { + return@apply + } + + providerOptions().validate() + baseUrl() + headers().ifPresent { it.validate() } + skipApiKeyFallback() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (headers.asKnown().getOrNull()?.validity() ?: 0) + + (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) + + class ProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val accessKeyId: JsonField, + private val region: JsonField, + private val secretAccessKey: JsonField, + private val sessionToken: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("accessKeyId") + @ExcludeMissing + accessKeyId: JsonField = JsonMissing.of(), + @JsonProperty("region") + @ExcludeMissing + region: JsonField = JsonMissing.of(), + @JsonProperty("secretAccessKey") + @ExcludeMissing + secretAccessKey: JsonField = JsonMissing.of(), + @JsonProperty("sessionToken") + @ExcludeMissing + sessionToken: JsonField = JsonMissing.of(), + ) : this(accessKeyId, region, secretAccessKey, sessionToken, mutableMapOf()) + + /** + * AWS access key ID for Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun accessKeyId(): String = accessKeyId.getRequired("accessKeyId") + + /** + * AWS region for Amazon Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun region(): String = region.getRequired("region") + + /** + * AWS secret access key for Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an + * unexpected value). + */ + fun secretAccessKey(): String = secretAccessKey.getRequired("secretAccessKey") + + /** + * Optional AWS session token for temporary credentials + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun sessionToken(): Optional = sessionToken.getOptional("sessionToken") + + /** + * Returns the raw JSON value of [accessKeyId]. + * + * Unlike [accessKeyId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("accessKeyId") + @ExcludeMissing + fun _accessKeyId(): JsonField = accessKeyId + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region + + /** + * Returns the raw JSON value of [secretAccessKey]. + * + * Unlike [secretAccessKey], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("secretAccessKey") + @ExcludeMissing + fun _secretAccessKey(): JsonField = secretAccessKey + + /** + * Returns the raw JSON value of [sessionToken]. + * + * Unlike [sessionToken], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("sessionToken") + @ExcludeMissing + fun _sessionToken(): JsonField = sessionToken + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ProviderOptions]. + * + * The following fields are required: + * ```java + * .accessKeyId() + * .region() + * .secretAccessKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ProviderOptions]. */ + class Builder internal constructor() { + + private var accessKeyId: JsonField? = null + private var region: JsonField? = null + private var secretAccessKey: JsonField? = null + private var sessionToken: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(providerOptions: ProviderOptions) = apply { + accessKeyId = providerOptions.accessKeyId + region = providerOptions.region + secretAccessKey = providerOptions.secretAccessKey + sessionToken = providerOptions.sessionToken + additionalProperties = providerOptions.additionalProperties.toMutableMap() + } + + /** AWS access key ID for Bedrock */ + fun accessKeyId(accessKeyId: String) = accessKeyId(JsonField.of(accessKeyId)) + + /** + * Sets [Builder.accessKeyId] to an arbitrary JSON value. + * + * You should usually call [Builder.accessKeyId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun accessKeyId(accessKeyId: JsonField) = apply { + this.accessKeyId = accessKeyId + } + + /** AWS region for Amazon Bedrock */ + fun region(region: String) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + /** AWS secret access key for Bedrock */ + fun secretAccessKey(secretAccessKey: String) = + secretAccessKey(JsonField.of(secretAccessKey)) + + /** + * Sets [Builder.secretAccessKey] to an arbitrary JSON value. + * + * You should usually call [Builder.secretAccessKey] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun secretAccessKey(secretAccessKey: JsonField) = apply { + this.secretAccessKey = secretAccessKey + } + + /** Optional AWS session token for temporary credentials */ + fun sessionToken(sessionToken: String) = + sessionToken(JsonField.of(sessionToken)) + + /** + * Sets [Builder.sessionToken] to an arbitrary JSON value. + * + * You should usually call [Builder.sessionToken] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun sessionToken(sessionToken: JsonField) = apply { + this.sessionToken = sessionToken + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .accessKeyId() + * .region() + * .secretAccessKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ProviderOptions = + ProviderOptions( + checkRequired("accessKeyId", accessKeyId), + checkRequired("region", region), + checkRequired("secretAccessKey", secretAccessKey), + sessionToken, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ProviderOptions = apply { + if (validated) { + return@apply + } + + accessKeyId() + region() + secretAccessKey() + sessionToken() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (accessKeyId.asKnown().isPresent) 1 else 0) + + (if (region.asKnown().isPresent) 1 else 0) + + (if (secretAccessKey.asKnown().isPresent) 1 else 0) + + (if (sessionToken.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProviderOptions && + accessKeyId == other.accessKeyId && + region == other.region && + secretAccessKey == other.secretAccessKey && + sessionToken == other.sessionToken && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + accessKeyId, + region, + secretAccessKey, + sessionToken, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ProviderOptions{accessKeyId=$accessKeyId, region=$region, secretAccessKey=$secretAccessKey, sessionToken=$sessionToken, additionalProperties=$additionalProperties}" + } + + /** Custom headers for the model provider */ + class Headers + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Headers]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Headers]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(headers: Headers) = apply { + additionalProperties = headers.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Headers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Headers = Headers(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Headers = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Headers{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BedrockAwsCredentialsModelClientOptions && + providerOptions == other.providerOptions && + baseUrl == other.baseUrl && + headers == other.headers && + skipApiKeyFallback == other.skipApiKeyFallback && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + providerOptions, + baseUrl, + headers, + skipApiKeyFallback, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BedrockAwsCredentialsModelClientOptions{providerOptions=$providerOptions, baseUrl=$baseUrl, headers=$headers, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" + } + + class GenericModelClientOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val apiKey: JsonField, + private val baseUrl: JsonField, + private val headers: JsonField, + private val providerOptions: JsonField, + private val skipApiKeyFallback: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("apiKey") + @ExcludeMissing + apiKey: JsonField = JsonMissing.of(), + @JsonProperty("baseURL") + @ExcludeMissing + baseUrl: JsonField = JsonMissing.of(), + @JsonProperty("headers") + @ExcludeMissing + headers: JsonField = JsonMissing.of(), + @JsonProperty("providerOptions") + @ExcludeMissing + providerOptions: JsonField = JsonMissing.of(), + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + skipApiKeyFallback: JsonField = JsonMissing.of(), + ) : this(apiKey, baseUrl, headers, providerOptions, skipApiKeyFallback, mutableMapOf()) + + /** + * API key for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun apiKey(): Optional = apiKey.getOptional("apiKey") + + /** + * Base URL for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun baseUrl(): Optional = baseUrl.getOptional("baseURL") + + /** + * Custom headers for the model provider + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun headers(): Optional = headers.getOptional("headers") + + /** + * Provider-specific options passed through to the AI SDK provider constructor. For + * Bedrock: { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { + * project, location, googleAuthOptions }. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun providerOptions(): Optional = + providerOptions.getOptional("providerOptions") + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this + * when auth is carried through providerOptions instead of an API key. + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun skipApiKeyFallback(): Optional = + skipApiKeyFallback.getOptional("skipApiKeyFallback") + + /** + * Returns the raw JSON value of [apiKey]. + * + * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey + + /** + * Returns the raw JSON value of [baseUrl]. + * + * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl + + /** + * Returns the raw JSON value of [headers]. + * + * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers + + /** + * Returns the raw JSON value of [providerOptions]. + * + * Unlike [providerOptions], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("providerOptions") + @ExcludeMissing + fun _providerOptions(): JsonField = providerOptions + + /** + * Returns the raw JSON value of [skipApiKeyFallback]. + * + * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("skipApiKeyFallback") + @ExcludeMissing + fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GenericModelClientOptions]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GenericModelClientOptions]. */ + class Builder internal constructor() { + + private var apiKey: JsonField = JsonMissing.of() + private var baseUrl: JsonField = JsonMissing.of() + private var headers: JsonField = JsonMissing.of() + private var providerOptions: JsonField = JsonMissing.of() + private var skipApiKeyFallback: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(genericModelClientOptions: GenericModelClientOptions) = apply { + apiKey = genericModelClientOptions.apiKey + baseUrl = genericModelClientOptions.baseUrl + headers = genericModelClientOptions.headers + providerOptions = genericModelClientOptions.providerOptions + skipApiKeyFallback = genericModelClientOptions.skipApiKeyFallback + additionalProperties = + genericModelClientOptions.additionalProperties.toMutableMap() + } + + /** API key for the model provider */ + fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) + + /** + * Sets [Builder.apiKey] to an arbitrary JSON value. + * + * You should usually call [Builder.apiKey] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } + + /** Base URL for the model provider */ + fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) + + /** + * Sets [Builder.baseUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.baseUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } + + /** Custom headers for the model provider */ + fun headers(headers: Headers) = headers(JsonField.of(headers)) + + /** + * Sets [Builder.headers] to an arbitrary JSON value. + * + * You should usually call [Builder.headers] with a well-typed [Headers] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun headers(headers: JsonField) = apply { this.headers = headers } + + /** + * Provider-specific options passed through to the AI SDK provider constructor. For + * Bedrock: { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { + * project, location, googleAuthOptions }. + */ + fun providerOptions(providerOptions: ProviderOptions) = + providerOptions(JsonField.of(providerOptions)) + + /** + * Sets [Builder.providerOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.providerOptions] with a well-typed + * [ProviderOptions] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun providerOptions(providerOptions: JsonField) = apply { + this.providerOptions = providerOptions + } + + /** + * Alias for calling [providerOptions] with + * `ProviderOptions.ofBedrockApiKey(bedrockApiKey)`. + */ + fun providerOptions(bedrockApiKey: ProviderOptions.BedrockApiKeyProviderOptions) = + providerOptions(ProviderOptions.ofBedrockApiKey(bedrockApiKey)) + + /** + * Alias for calling [providerOptions] with + * `ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. + */ + fun providerOptions( + bedrockAwsCredentials: ProviderOptions.BedrockAwsCredentialsProviderOptions + ) = providerOptions(ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)) + + /** + * Alias for calling [providerOptions] with + * `ProviderOptions.ofGoogleVertex(googleVertex)`. + */ + fun providerOptions(googleVertex: ProviderOptions.GoogleVertexProviderOptions) = + providerOptions(ProviderOptions.ofGoogleVertex(googleVertex)) + + /** + * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use + * this when auth is carried through providerOptions instead of an API key. + */ + fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = + skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) + + /** + * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. + * + * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { + this.skipApiKeyFallback = skipApiKeyFallback + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GenericModelClientOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GenericModelClientOptions = + GenericModelClientOptions( + apiKey, + baseUrl, + headers, + providerOptions, + skipApiKeyFallback, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GenericModelClientOptions = apply { + if (validated) { + return@apply + } + + apiKey() + baseUrl() + headers().ifPresent { it.validate() } + providerOptions().ifPresent { it.validate() } + skipApiKeyFallback() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (apiKey.asKnown().isPresent) 1 else 0) + + (if (baseUrl.asKnown().isPresent) 1 else 0) + + (headers.asKnown().getOrNull()?.validity() ?: 0) + + (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + + (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) + + /** Custom headers for the model provider */ + class Headers + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Headers]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Headers]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(headers: Headers) = apply { + additionalProperties = headers.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Headers]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Headers = Headers(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Headers = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Headers{additionalProperties=$additionalProperties}" + } + + /** + * Provider-specific options passed through to the AI SDK provider constructor. For + * Bedrock: { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { + * project, location, googleAuthOptions }. + */ + @JsonDeserialize(using = ProviderOptions.Deserializer::class) + @JsonSerialize(using = ProviderOptions.Serializer::class) + class ProviderOptions + private constructor( + private val bedrockApiKey: BedrockApiKeyProviderOptions? = null, + private val bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions? = null, + private val googleVertex: GoogleVertexProviderOptions? = null, + private val _json: JsonValue? = null, + ) { + + fun bedrockApiKey(): Optional = + Optional.ofNullable(bedrockApiKey) + + fun bedrockAwsCredentials(): Optional = + Optional.ofNullable(bedrockAwsCredentials) + + fun googleVertex(): Optional = + Optional.ofNullable(googleVertex) + + fun isBedrockApiKey(): Boolean = bedrockApiKey != null + + fun isBedrockAwsCredentials(): Boolean = bedrockAwsCredentials != null + + fun isGoogleVertex(): Boolean = googleVertex != null + + fun asBedrockApiKey(): BedrockApiKeyProviderOptions = + bedrockApiKey.getOrThrow("bedrockApiKey") + + fun asBedrockAwsCredentials(): BedrockAwsCredentialsProviderOptions = + bedrockAwsCredentials.getOrThrow("bedrockAwsCredentials") + + fun asGoogleVertex(): GoogleVertexProviderOptions = + googleVertex.getOrThrow("googleVertex") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + bedrockApiKey != null -> visitor.visitBedrockApiKey(bedrockApiKey) + bedrockAwsCredentials != null -> + visitor.visitBedrockAwsCredentials(bedrockAwsCredentials) + googleVertex != null -> visitor.visitGoogleVertex(googleVertex) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ProviderOptions = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitBedrockApiKey( + bedrockApiKey: BedrockApiKeyProviderOptions + ) { + bedrockApiKey.validate() + } + + override fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ) { + bedrockAwsCredentials.validate() + } + + override fun visitGoogleVertex( + googleVertex: GoogleVertexProviderOptions + ) { + googleVertex.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitBedrockApiKey( + bedrockApiKey: BedrockApiKeyProviderOptions + ) = bedrockApiKey.validity() + + override fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ) = bedrockAwsCredentials.validity() + + override fun visitGoogleVertex( + googleVertex: GoogleVertexProviderOptions + ) = googleVertex.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is ProviderOptions && + bedrockApiKey == other.bedrockApiKey && + bedrockAwsCredentials == other.bedrockAwsCredentials && + googleVertex == other.googleVertex + } + + override fun hashCode(): Int = + Objects.hash(bedrockApiKey, bedrockAwsCredentials, googleVertex) + + override fun toString(): String = + when { + bedrockApiKey != null -> "ProviderOptions{bedrockApiKey=$bedrockApiKey}" + bedrockAwsCredentials != null -> + "ProviderOptions{bedrockAwsCredentials=$bedrockAwsCredentials}" + googleVertex != null -> "ProviderOptions{googleVertex=$googleVertex}" + _json != null -> "ProviderOptions{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ProviderOptions") + } + + companion object { + + @JvmStatic + fun ofBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) = + ProviderOptions(bedrockApiKey = bedrockApiKey) + + @JvmStatic + fun ofBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ) = ProviderOptions(bedrockAwsCredentials = bedrockAwsCredentials) + + @JvmStatic + fun ofGoogleVertex(googleVertex: GoogleVertexProviderOptions) = + ProviderOptions(googleVertex = googleVertex) + } + + /** + * An interface that defines how to map each variant of [ProviderOptions] to a value + * of type [T]. + */ + interface Visitor { + + fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions): T + + fun visitBedrockAwsCredentials( + bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions + ): T + + fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions): T + + /** + * Maps an unknown variant of [ProviderOptions] to a value of type [T]. + * + * An instance of [ProviderOptions] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if + * the SDK is on an older version than the API, then the API may respond with + * new variants that the SDK is unaware of. + * + * @throws StagehandInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw StagehandInvalidDataException("Unknown ProviderOptions: $json") + } + } + + internal class Deserializer : + BaseDeserializer(ProviderOptions::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ProviderOptions { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { ProviderOptions(bedrockApiKey = it, _json = json) }, + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { + ProviderOptions( + bedrockAwsCredentials = it, + _json = json, + ) + }, + tryDeserialize( + node, + jacksonTypeRef(), + ) + ?.let { ProviderOptions(googleVertex = it, _json = json) }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely + // incompatible with all the possible variants (e.g. deserializing from + // boolean). + 0 -> ProviderOptions(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use + // the first completely valid match, or simply the first match if none + // are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(ProviderOptions::class) { + + override fun serialize( + value: ProviderOptions, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.bedrockApiKey != null -> + generator.writeObject(value.bedrockApiKey) + value.bedrockAwsCredentials != null -> + generator.writeObject(value.bedrockAwsCredentials) + value.googleVertex != null -> generator.writeObject(value.googleVertex) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ProviderOptions") + } + } + } + + class BedrockApiKeyProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val region: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("region") + @ExcludeMissing + region: JsonField = JsonMissing.of() + ) : this(region, mutableMapOf()) + + /** + * AWS region for Amazon Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun region(): String = region.getRequired("region") + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("region") + @ExcludeMissing + fun _region(): JsonField = region + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BedrockApiKeyProviderOptions]. + * + * The following fields are required: + * ```java + * .region() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BedrockApiKeyProviderOptions]. */ + class Builder internal constructor() { + + private var region: JsonField? = null + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from( + bedrockApiKeyProviderOptions: BedrockApiKeyProviderOptions + ) = apply { + region = bedrockApiKeyProviderOptions.region + additionalProperties = + bedrockApiKeyProviderOptions.additionalProperties.toMutableMap() + } + + /** AWS region for Amazon Bedrock */ + fun region(region: String) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BedrockApiKeyProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .region() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BedrockApiKeyProviderOptions = + BedrockApiKeyProviderOptions( + checkRequired("region", region), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BedrockApiKeyProviderOptions = apply { + if (validated) { + return@apply + } + + region() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (if (region.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BedrockApiKeyProviderOptions && + region == other.region && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(region, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BedrockApiKeyProviderOptions{region=$region, additionalProperties=$additionalProperties}" + } + + class BedrockAwsCredentialsProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val accessKeyId: JsonField, + private val region: JsonField, + private val secretAccessKey: JsonField, + private val sessionToken: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("accessKeyId") + @ExcludeMissing + accessKeyId: JsonField = JsonMissing.of(), + @JsonProperty("region") + @ExcludeMissing + region: JsonField = JsonMissing.of(), + @JsonProperty("secretAccessKey") + @ExcludeMissing + secretAccessKey: JsonField = JsonMissing.of(), + @JsonProperty("sessionToken") + @ExcludeMissing + sessionToken: JsonField = JsonMissing.of(), + ) : this(accessKeyId, region, secretAccessKey, sessionToken, mutableMapOf()) + + /** + * AWS access key ID for Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun accessKeyId(): String = accessKeyId.getRequired("accessKeyId") + + /** + * AWS region for Amazon Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun region(): String = region.getRequired("region") + + /** + * AWS secret access key for Bedrock + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type or is unexpectedly missing or null (e.g. if the server responded with + * an unexpected value). + */ + fun secretAccessKey(): String = secretAccessKey.getRequired("secretAccessKey") + + /** + * Optional AWS session token for temporary credentials + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun sessionToken(): Optional = sessionToken.getOptional("sessionToken") + + /** + * Returns the raw JSON value of [accessKeyId]. + * + * Unlike [accessKeyId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("accessKeyId") + @ExcludeMissing + fun _accessKeyId(): JsonField = accessKeyId + + /** + * Returns the raw JSON value of [region]. + * + * Unlike [region], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("region") + @ExcludeMissing + fun _region(): JsonField = region + + /** + * Returns the raw JSON value of [secretAccessKey]. + * + * Unlike [secretAccessKey], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("secretAccessKey") + @ExcludeMissing + fun _secretAccessKey(): JsonField = secretAccessKey + + /** + * Returns the raw JSON value of [sessionToken]. + * + * Unlike [sessionToken], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("sessionToken") + @ExcludeMissing + fun _sessionToken(): JsonField = sessionToken + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [BedrockAwsCredentialsProviderOptions]. + * + * The following fields are required: + * ```java + * .accessKeyId() + * .region() + * .secretAccessKey() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BedrockAwsCredentialsProviderOptions]. */ + class Builder internal constructor() { + + private var accessKeyId: JsonField? = null + private var region: JsonField? = null + private var secretAccessKey: JsonField? = null + private var sessionToken: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from( + bedrockAwsCredentialsProviderOptions: + BedrockAwsCredentialsProviderOptions + ) = apply { + accessKeyId = bedrockAwsCredentialsProviderOptions.accessKeyId + region = bedrockAwsCredentialsProviderOptions.region + secretAccessKey = bedrockAwsCredentialsProviderOptions.secretAccessKey + sessionToken = bedrockAwsCredentialsProviderOptions.sessionToken + additionalProperties = + bedrockAwsCredentialsProviderOptions.additionalProperties + .toMutableMap() + } + + /** AWS access key ID for Bedrock */ + fun accessKeyId(accessKeyId: String) = + accessKeyId(JsonField.of(accessKeyId)) + + /** + * Sets [Builder.accessKeyId] to an arbitrary JSON value. + * + * You should usually call [Builder.accessKeyId] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun accessKeyId(accessKeyId: JsonField) = apply { + this.accessKeyId = accessKeyId + } + + /** AWS region for Amazon Bedrock */ + fun region(region: String) = region(JsonField.of(region)) + + /** + * Sets [Builder.region] to an arbitrary JSON value. + * + * You should usually call [Builder.region] with a well-typed [String] value + * instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun region(region: JsonField) = apply { this.region = region } + + /** AWS secret access key for Bedrock */ + fun secretAccessKey(secretAccessKey: String) = + secretAccessKey(JsonField.of(secretAccessKey)) + + /** + * Sets [Builder.secretAccessKey] to an arbitrary JSON value. + * + * You should usually call [Builder.secretAccessKey] with a well-typed + * [String] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun secretAccessKey(secretAccessKey: JsonField) = apply { + this.secretAccessKey = secretAccessKey + } + + /** Optional AWS session token for temporary credentials */ + fun sessionToken(sessionToken: String) = + sessionToken(JsonField.of(sessionToken)) + + /** + * Sets [Builder.sessionToken] to an arbitrary JSON value. + * + * You should usually call [Builder.sessionToken] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun sessionToken(sessionToken: JsonField) = apply { + this.sessionToken = sessionToken + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BedrockAwsCredentialsProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .accessKeyId() + * .region() + * .secretAccessKey() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): BedrockAwsCredentialsProviderOptions = + BedrockAwsCredentialsProviderOptions( + checkRequired("accessKeyId", accessKeyId), + checkRequired("region", region), + checkRequired("secretAccessKey", secretAccessKey), + sessionToken, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): BedrockAwsCredentialsProviderOptions = apply { + if (validated) { + return@apply + } + + accessKeyId() + region() + secretAccessKey() + sessionToken() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (accessKeyId.asKnown().isPresent) 1 else 0) + + (if (region.asKnown().isPresent) 1 else 0) + + (if (secretAccessKey.asKnown().isPresent) 1 else 0) + + (if (sessionToken.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BedrockAwsCredentialsProviderOptions && + accessKeyId == other.accessKeyId && + region == other.region && + secretAccessKey == other.secretAccessKey && + sessionToken == other.sessionToken && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + accessKeyId, + region, + secretAccessKey, + sessionToken, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "BedrockAwsCredentialsProviderOptions{accessKeyId=$accessKeyId, region=$region, secretAccessKey=$secretAccessKey, sessionToken=$sessionToken, additionalProperties=$additionalProperties}" + } + + class GoogleVertexProviderOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val googleAuthOptions: JsonField, + private val headers: JsonField, + private val location: JsonField, + private val project: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("googleAuthOptions") + @ExcludeMissing + googleAuthOptions: JsonField = JsonMissing.of(), + @JsonProperty("headers") + @ExcludeMissing + headers: JsonField = JsonMissing.of(), + @JsonProperty("location") + @ExcludeMissing + location: JsonField = JsonMissing.of(), + @JsonProperty("project") + @ExcludeMissing + project: JsonField = JsonMissing.of(), + ) : this(googleAuthOptions, headers, location, project, mutableMapOf()) + + /** + * Optional Google auth options for Vertex AI + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun googleAuthOptions(): Optional = + googleAuthOptions.getOptional("googleAuthOptions") + + /** + * Custom headers for Vertex AI requests + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun headers(): Optional = headers.getOptional("headers") + + /** + * Google Cloud location for Vertex AI + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun location(): Optional = location.getOptional("location") + + /** + * Google Cloud project ID for Vertex AI + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun project(): Optional = project.getOptional("project") + + /** + * Returns the raw JSON value of [googleAuthOptions]. + * + * Unlike [googleAuthOptions], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("googleAuthOptions") + @ExcludeMissing + fun _googleAuthOptions(): JsonField = googleAuthOptions + + /** + * Returns the raw JSON value of [headers]. + * + * Unlike [headers], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("headers") + @ExcludeMissing + fun _headers(): JsonField = headers + + /** + * Returns the raw JSON value of [location]. + * + * Unlike [location], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("location") + @ExcludeMissing + fun _location(): JsonField = location + + /** + * Returns the raw JSON value of [project]. + * + * Unlike [project], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("project") + @ExcludeMissing + fun _project(): JsonField = project + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GoogleVertexProviderOptions]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GoogleVertexProviderOptions]. */ + class Builder internal constructor() { + + private var googleAuthOptions: JsonField = + JsonMissing.of() + private var headers: JsonField = JsonMissing.of() + private var location: JsonField = JsonMissing.of() + private var project: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from( + googleVertexProviderOptions: GoogleVertexProviderOptions + ) = apply { + googleAuthOptions = googleVertexProviderOptions.googleAuthOptions + headers = googleVertexProviderOptions.headers + location = googleVertexProviderOptions.location + project = googleVertexProviderOptions.project + additionalProperties = + googleVertexProviderOptions.additionalProperties.toMutableMap() + } + + /** Optional Google auth options for Vertex AI */ + fun googleAuthOptions(googleAuthOptions: GoogleAuthOptions) = + googleAuthOptions(JsonField.of(googleAuthOptions)) + + /** + * Sets [Builder.googleAuthOptions] to an arbitrary JSON value. + * + * You should usually call [Builder.googleAuthOptions] with a well-typed + * [GoogleAuthOptions] value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun googleAuthOptions(googleAuthOptions: JsonField) = + apply { + this.googleAuthOptions = googleAuthOptions + } + + /** Custom headers for Vertex AI requests */ + fun headers(headers: Headers) = headers(JsonField.of(headers)) + + /** + * Sets [Builder.headers] to an arbitrary JSON value. + * + * You should usually call [Builder.headers] with a well-typed [Headers] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun headers(headers: JsonField) = apply { this.headers = headers } + + /** Google Cloud location for Vertex AI */ + fun location(location: String) = location(JsonField.of(location)) + + /** + * Sets [Builder.location] to an arbitrary JSON value. + * + * You should usually call [Builder.location] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun location(location: JsonField) = apply { + this.location = location + } + + /** Google Cloud project ID for Vertex AI */ + fun project(project: String) = project(JsonField.of(project)) + + /** + * Sets [Builder.project] to an arbitrary JSON value. + * + * You should usually call [Builder.project] with a well-typed [String] + * value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun project(project: JsonField) = apply { this.project = project } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GoogleVertexProviderOptions]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GoogleVertexProviderOptions = + GoogleVertexProviderOptions( + googleAuthOptions, + headers, + location, + project, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GoogleVertexProviderOptions = apply { + if (validated) { + return@apply + } + + googleAuthOptions().ifPresent { it.validate() } + headers().ifPresent { it.validate() } + location() + project() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (googleAuthOptions.asKnown().getOrNull()?.validity() ?: 0) + + (headers.asKnown().getOrNull()?.validity() ?: 0) + + (if (location.asKnown().isPresent) 1 else 0) + + (if (project.asKnown().isPresent) 1 else 0) + + /** Optional Google auth options for Vertex AI */ + class GoogleAuthOptions + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val credentials: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("credentials") + @ExcludeMissing + credentials: JsonField = JsonMissing.of() + ) : this(credentials, mutableMapOf()) + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected + * type (e.g. if the server responded with an unexpected value). + */ + fun credentials(): Optional = + credentials.getOptional("credentials") + + /** + * Returns the raw JSON value of [credentials]. + * + * Unlike [credentials], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("credentials") + @ExcludeMissing + fun _credentials(): JsonField = credentials + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [GoogleAuthOptions]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GoogleAuthOptions]. */ + class Builder internal constructor() { + + private var credentials: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(googleAuthOptions: GoogleAuthOptions) = apply { + credentials = googleAuthOptions.credentials + additionalProperties = + googleAuthOptions.additionalProperties.toMutableMap() + } + + fun credentials(credentials: Credentials) = + credentials(JsonField.of(credentials)) + + /** + * Sets [Builder.credentials] to an arbitrary JSON value. + * + * You should usually call [Builder.credentials] with a well-typed + * [Credentials] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun credentials(credentials: JsonField) = apply { + this.credentials = credentials + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GoogleAuthOptions]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): GoogleAuthOptions = + GoogleAuthOptions(credentials, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): GoogleAuthOptions = apply { + if (validated) { + return@apply + } + + credentials().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (credentials.asKnown().getOrNull()?.validity() ?: 0) + + class Credentials + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val authProviderX509CertUrl: JsonField, + private val authUri: JsonField, + private val clientEmail: JsonField, + private val clientId: JsonField, + private val clientX509CertUrl: JsonField, + private val privateKey: JsonField, + private val privateKeyId: JsonField, + private val projectId: JsonField, + private val tokenUri: JsonField, + private val type: JsonField, + private val universeDomain: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("auth_provider_x509_cert_url") + @ExcludeMissing + authProviderX509CertUrl: JsonField = JsonMissing.of(), + @JsonProperty("auth_uri") + @ExcludeMissing + authUri: JsonField = JsonMissing.of(), + @JsonProperty("client_email") + @ExcludeMissing + clientEmail: JsonField = JsonMissing.of(), + @JsonProperty("client_id") + @ExcludeMissing + clientId: JsonField = JsonMissing.of(), + @JsonProperty("client_x509_cert_url") + @ExcludeMissing + clientX509CertUrl: JsonField = JsonMissing.of(), + @JsonProperty("private_key") + @ExcludeMissing + privateKey: JsonField = JsonMissing.of(), + @JsonProperty("private_key_id") + @ExcludeMissing + privateKeyId: JsonField = JsonMissing.of(), + @JsonProperty("project_id") + @ExcludeMissing + projectId: JsonField = JsonMissing.of(), + @JsonProperty("token_uri") + @ExcludeMissing + tokenUri: JsonField = JsonMissing.of(), + @JsonProperty("type") + @ExcludeMissing + type: JsonField = JsonMissing.of(), + @JsonProperty("universe_domain") + @ExcludeMissing + universeDomain: JsonField = JsonMissing.of(), + ) : this( + authProviderX509CertUrl, + authUri, + clientEmail, + clientId, + clientX509CertUrl, + privateKey, + privateKeyId, + projectId, + tokenUri, + type, + universeDomain, + mutableMapOf(), + ) + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun authProviderX509CertUrl(): Optional = + authProviderX509CertUrl.getOptional("auth_provider_x509_cert_url") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun authUri(): Optional = authUri.getOptional("auth_uri") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun clientEmail(): Optional = + clientEmail.getOptional("client_email") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun clientId(): Optional = clientId.getOptional("client_id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun clientX509CertUrl(): Optional = + clientX509CertUrl.getOptional("client_x509_cert_url") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun privateKey(): Optional = + privateKey.getOptional("private_key") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun privateKeyId(): Optional = + privateKeyId.getOptional("private_key_id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun projectId(): Optional = projectId.getOptional("project_id") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun tokenUri(): Optional = tokenUri.getOptional("token_uri") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * @throws StagehandInvalidDataException if the JSON field has an + * unexpected type (e.g. if the server responded with an unexpected + * value). + */ + fun universeDomain(): Optional = + universeDomain.getOptional("universe_domain") + + /** + * Returns the raw JSON value of [authProviderX509CertUrl]. + * + * Unlike [authProviderX509CertUrl], this method doesn't throw if the + * JSON field has an unexpected type. + */ + @JsonProperty("auth_provider_x509_cert_url") + @ExcludeMissing + fun _authProviderX509CertUrl(): JsonField = + authProviderX509CertUrl + + /** + * Returns the raw JSON value of [authUri]. + * + * Unlike [authUri], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("auth_uri") + @ExcludeMissing + fun _authUri(): JsonField = authUri + + /** + * Returns the raw JSON value of [clientEmail]. + * + * Unlike [clientEmail], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("client_email") + @ExcludeMissing + fun _clientEmail(): JsonField = clientEmail + + /** + * Returns the raw JSON value of [clientId]. + * + * Unlike [clientId], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("client_id") + @ExcludeMissing + fun _clientId(): JsonField = clientId + + /** + * Returns the raw JSON value of [clientX509CertUrl]. + * + * Unlike [clientX509CertUrl], this method doesn't throw if the JSON + * field has an unexpected type. + */ + @JsonProperty("client_x509_cert_url") + @ExcludeMissing + fun _clientX509CertUrl(): JsonField = clientX509CertUrl + + /** + * Returns the raw JSON value of [privateKey]. + * + * Unlike [privateKey], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("private_key") + @ExcludeMissing + fun _privateKey(): JsonField = privateKey + + /** + * Returns the raw JSON value of [privateKeyId]. + * + * Unlike [privateKeyId], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("private_key_id") + @ExcludeMissing + fun _privateKeyId(): JsonField = privateKeyId + + /** + * Returns the raw JSON value of [projectId]. + * + * Unlike [projectId], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("project_id") + @ExcludeMissing + fun _projectId(): JsonField = projectId + + /** + * Returns the raw JSON value of [tokenUri]. + * + * Unlike [tokenUri], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("token_uri") + @ExcludeMissing + fun _tokenUri(): JsonField = tokenUri + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("type") + @ExcludeMissing + fun _type(): JsonField = type + + /** + * Returns the raw JSON value of [universeDomain]. + * + * Unlike [universeDomain], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("universe_domain") + @ExcludeMissing + fun _universeDomain(): JsonField = universeDomain + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [Credentials]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Credentials]. */ + class Builder internal constructor() { + + private var authProviderX509CertUrl: JsonField = + JsonMissing.of() + private var authUri: JsonField = JsonMissing.of() + private var clientEmail: JsonField = JsonMissing.of() + private var clientId: JsonField = JsonMissing.of() + private var clientX509CertUrl: JsonField = JsonMissing.of() + private var privateKey: JsonField = JsonMissing.of() + private var privateKeyId: JsonField = JsonMissing.of() + private var projectId: JsonField = JsonMissing.of() + private var tokenUri: JsonField = JsonMissing.of() + private var type: JsonField = JsonMissing.of() + private var universeDomain: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(credentials: Credentials) = apply { + authProviderX509CertUrl = credentials.authProviderX509CertUrl + authUri = credentials.authUri + clientEmail = credentials.clientEmail + clientId = credentials.clientId + clientX509CertUrl = credentials.clientX509CertUrl + privateKey = credentials.privateKey + privateKeyId = credentials.privateKeyId + projectId = credentials.projectId + tokenUri = credentials.tokenUri + type = credentials.type + universeDomain = credentials.universeDomain + additionalProperties = + credentials.additionalProperties.toMutableMap() + } + + fun authProviderX509CertUrl(authProviderX509CertUrl: String) = + authProviderX509CertUrl(JsonField.of(authProviderX509CertUrl)) + + /** + * Sets [Builder.authProviderX509CertUrl] to an arbitrary JSON + * value. + * + * You should usually call [Builder.authProviderX509CertUrl] with a + * well-typed [String] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun authProviderX509CertUrl( + authProviderX509CertUrl: JsonField + ) = apply { this.authProviderX509CertUrl = authProviderX509CertUrl } + + fun authUri(authUri: String) = authUri(JsonField.of(authUri)) + + /** + * Sets [Builder.authUri] to an arbitrary JSON value. + * + * You should usually call [Builder.authUri] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun authUri(authUri: JsonField) = apply { + this.authUri = authUri + } + + fun clientEmail(clientEmail: String) = + clientEmail(JsonField.of(clientEmail)) + + /** + * Sets [Builder.clientEmail] to an arbitrary JSON value. + * + * You should usually call [Builder.clientEmail] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun clientEmail(clientEmail: JsonField) = apply { + this.clientEmail = clientEmail + } + + fun clientId(clientId: String) = clientId(JsonField.of(clientId)) + + /** + * Sets [Builder.clientId] to an arbitrary JSON value. + * + * You should usually call [Builder.clientId] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun clientId(clientId: JsonField) = apply { + this.clientId = clientId + } + + fun clientX509CertUrl(clientX509CertUrl: String) = + clientX509CertUrl(JsonField.of(clientX509CertUrl)) + + /** + * Sets [Builder.clientX509CertUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.clientX509CertUrl] with a + * well-typed [String] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun clientX509CertUrl(clientX509CertUrl: JsonField) = + apply { + this.clientX509CertUrl = clientX509CertUrl + } + + fun privateKey(privateKey: String) = + privateKey(JsonField.of(privateKey)) + + /** + * Sets [Builder.privateKey] to an arbitrary JSON value. + * + * You should usually call [Builder.privateKey] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun privateKey(privateKey: JsonField) = apply { + this.privateKey = privateKey + } + + fun privateKeyId(privateKeyId: String) = + privateKeyId(JsonField.of(privateKeyId)) + + /** + * Sets [Builder.privateKeyId] to an arbitrary JSON value. + * + * You should usually call [Builder.privateKeyId] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun privateKeyId(privateKeyId: JsonField) = apply { + this.privateKeyId = privateKeyId + } + + fun projectId(projectId: String) = + projectId(JsonField.of(projectId)) + + /** + * Sets [Builder.projectId] to an arbitrary JSON value. + * + * You should usually call [Builder.projectId] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun projectId(projectId: JsonField) = apply { + this.projectId = projectId + } + + fun tokenUri(tokenUri: String) = tokenUri(JsonField.of(tokenUri)) + + /** + * Sets [Builder.tokenUri] to an arbitrary JSON value. + * + * You should usually call [Builder.tokenUri] with a well-typed + * [String] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun tokenUri(tokenUri: JsonField) = apply { + this.tokenUri = tokenUri + } + + fun type(type: String) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [String] + * value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun universeDomain(universeDomain: String) = + universeDomain(JsonField.of(universeDomain)) + + /** + * Sets [Builder.universeDomain] to an arbitrary JSON value. + * + * You should usually call [Builder.universeDomain] with a + * well-typed [String] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun universeDomain(universeDomain: JsonField) = apply { + this.universeDomain = universeDomain + } + + fun additionalProperties( + additionalProperties: Map + ) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Credentials]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): Credentials = + Credentials( + authProviderX509CertUrl, + authUri, + clientEmail, + clientId, + clientX509CertUrl, + privateKey, + privateKeyId, + projectId, + tokenUri, + type, + universeDomain, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Credentials = apply { + if (validated) { + return@apply + } + + authProviderX509CertUrl() + authUri() + clientEmail() + clientId() + clientX509CertUrl() + privateKey() + privateKeyId() + projectId() + tokenUri() + type() + universeDomain() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in + * this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (authProviderX509CertUrl.asKnown().isPresent) 1 else 0) + + (if (authUri.asKnown().isPresent) 1 else 0) + + (if (clientEmail.asKnown().isPresent) 1 else 0) + + (if (clientId.asKnown().isPresent) 1 else 0) + + (if (clientX509CertUrl.asKnown().isPresent) 1 else 0) + + (if (privateKey.asKnown().isPresent) 1 else 0) + + (if (privateKeyId.asKnown().isPresent) 1 else 0) + + (if (projectId.asKnown().isPresent) 1 else 0) + + (if (tokenUri.asKnown().isPresent) 1 else 0) + + (if (type.asKnown().isPresent) 1 else 0) + + (if (universeDomain.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Credentials && + authProviderX509CertUrl == other.authProviderX509CertUrl && + authUri == other.authUri && + clientEmail == other.clientEmail && + clientId == other.clientId && + clientX509CertUrl == other.clientX509CertUrl && + privateKey == other.privateKey && + privateKeyId == other.privateKeyId && + projectId == other.projectId && + tokenUri == other.tokenUri && + type == other.type && + universeDomain == other.universeDomain && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + authProviderX509CertUrl, + authUri, + clientEmail, + clientId, + clientX509CertUrl, + privateKey, + privateKeyId, + projectId, + tokenUri, + type, + universeDomain, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Credentials{authProviderX509CertUrl=$authProviderX509CertUrl, authUri=$authUri, clientEmail=$clientEmail, clientId=$clientId, clientX509CertUrl=$clientX509CertUrl, privateKey=$privateKey, privateKeyId=$privateKeyId, projectId=$projectId, tokenUri=$tokenUri, type=$type, universeDomain=$universeDomain, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GoogleAuthOptions && + credentials == other.credentials && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(credentials, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GoogleAuthOptions{credentials=$credentials, additionalProperties=$additionalProperties}" + } + + /** Custom headers for Vertex AI requests */ + class Headers + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Headers]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Headers]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = + mutableMapOf() + + @JvmSynthetic + internal fun from(headers: Headers) = apply { + additionalProperties = headers.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties( + additionalProperties: Map + ) = apply { this.additionalProperties.putAll(additionalProperties) } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Headers]. + * + * Further updates to this [Builder] will not mutate the returned + * instance. + */ + fun build(): Headers = Headers(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Headers = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this + * object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Headers && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Headers{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GoogleVertexProviderOptions && + googleAuthOptions == other.googleAuthOptions && + headers == other.headers && + location == other.location && + project == other.project && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + googleAuthOptions, + headers, + location, + project, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GoogleVertexProviderOptions{googleAuthOptions=$googleAuthOptions, headers=$headers, location=$location, project=$project, additionalProperties=$additionalProperties}" + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is GenericModelClientOptions && + apiKey == other.apiKey && + baseUrl == other.baseUrl && + headers == other.headers && + providerOptions == other.providerOptions && + skipApiKeyFallback == other.skipApiKeyFallback && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + apiKey, + baseUrl, + headers, + providerOptions, + skipApiKeyFallback, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GenericModelClientOptions{apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, providerOptions=$providerOptions, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" + } + } + /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt index 4584374..443104b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -30,8 +30,8 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * Server-Sent Event emitted during streaming responses. Events are sent as `event: \ndata: - * \n\n`, where the JSON payload has the shape `{ data, type, id }`. + * Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. Key + * order: data (with status first), type, id. */ class StreamEvent @JsonCreator(mode = JsonCreator.Mode.DISABLED) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index 6e3b3d0..1326d37 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -14,27 +14,42 @@ internal class ModelConfigTest { fun create() { val modelConfig = ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() - assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5.4-mini") + assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5-nano") assertThat(modelConfig.apiKey()).contains("sk-some-openai-api-key") assertThat(modelConfig.baseUrl()).contains("https://api.openai.com/v1") assertThat(modelConfig.headers()) .contains( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) .build() ) assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI) + assertThat(modelConfig.providerOptions()) + .contains( + ModelConfig.ProviderOptions.ofBedrockApiKey( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + ) + assertThat(modelConfig.skipApiKeyFallback()).contains(true) } @Test @@ -42,15 +57,21 @@ internal class ModelConfigTest { val jsonMapper = jsonMapper() val modelConfig = ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() val roundtrippedModelConfig = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index 31ef59b..ac1315c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -20,15 +20,24 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -76,15 +85,25 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -136,15 +155,25 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -176,15 +205,24 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index f040cad..e2c6f96 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -19,29 +19,47 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -55,8 +73,6 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -95,29 +111,49 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -131,8 +167,6 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -175,29 +209,49 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -211,8 +265,6 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -227,29 +279,47 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -264,8 +334,6 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) assertThat(body.frameId()).contains("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index d84a3f9..f14f0a4 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -20,15 +20,24 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -65,15 +74,25 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -114,15 +133,25 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -146,15 +175,24 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 08f0c13..fc07b50 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -20,15 +20,24 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -74,15 +83,25 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -132,15 +151,25 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -172,15 +201,24 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 7ebe44e..eef7a55 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -152,6 +152,27 @@ internal class SessionStartParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -307,6 +328,27 @@ internal class SessionStartParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -475,6 +517,27 @@ internal class SessionStartParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -624,6 +687,30 @@ internal class SessionStartParamsTest { assertThat(body.browserbaseSessionId()).contains("browserbaseSessionID") assertThat(body.domSettleTimeoutMs()).contains(5000.0) assertThat(body.experimental()).contains(true) + assertThat(body.modelClientOptions()) + .contains( + SessionStartParams.ModelClientOptions.ofBedrockApiKey( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) + ) assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index a3bc8a0..194631c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -233,6 +233,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -419,6 +446,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -605,6 +659,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -791,6 +872,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -977,6 +1085,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1163,6 +1298,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1349,6 +1511,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1535,6 +1724,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1721,6 +1937,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1907,6 +2150,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2093,6 +2363,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2279,6 +2576,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2465,6 +2789,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2651,6 +3002,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2837,6 +3215,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -3023,6 +3428,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -3207,6 +3639,33 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index f423bd2..233fdfd 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -192,6 +192,27 @@ internal class ServiceParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -226,15 +247,25 @@ internal class ServiceParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 3635e44..0d1d6b0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -40,15 +40,25 @@ internal class SessionServiceAsyncTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -97,15 +107,25 @@ internal class SessionServiceAsyncTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -177,29 +197,49 @@ internal class SessionServiceAsyncTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -213,8 +253,6 @@ internal class SessionServiceAsyncTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -247,29 +285,49 @@ internal class SessionServiceAsyncTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -283,8 +341,6 @@ internal class SessionServiceAsyncTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -319,15 +375,25 @@ internal class SessionServiceAsyncTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -368,15 +434,25 @@ internal class SessionServiceAsyncTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -451,15 +527,25 @@ internal class SessionServiceAsyncTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -509,15 +595,25 @@ internal class SessionServiceAsyncTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -731,6 +827,33 @@ internal class SessionServiceAsyncTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 15ae6c4..cf8b728 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -40,15 +40,25 @@ internal class SessionServiceTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -96,15 +106,25 @@ internal class SessionServiceTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -175,29 +195,49 @@ internal class SessionServiceTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -211,8 +251,6 @@ internal class SessionServiceTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -244,29 +282,49 @@ internal class SessionServiceTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -280,8 +338,6 @@ internal class SessionServiceTest { ) .highlightCursor(true) .maxSteps(20.0) - .toolTimeout(30000.0) - .useSearch(true) .build() ) .frameId("frameId") @@ -316,15 +372,25 @@ internal class SessionServiceTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -364,15 +430,25 @@ internal class SessionServiceTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -446,15 +522,25 @@ internal class SessionServiceTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -503,15 +589,25 @@ internal class SessionServiceTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5.4-mini") + .modelName("openai/gpt-5-nano") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("foo", JsonValue.from("string")) + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) .build() ) .provider(ModelConfig.Provider.OPENAI) + .providerOptions( + ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -724,6 +820,33 @@ internal class SessionServiceTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) + .modelClientOptions( + SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions + .builder() + .apiKey("bedrock-short-term-api-key") + .providerOptions( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .ProviderOptions + .builder() + .region("us-east-1") + .build() + ) + .baseUrl("https://api.openai.com/v1") + .headers( + SessionStartParams.ModelClientOptions + .BedrockApiKeyModelClientOptions + .Headers + .builder() + .putAdditionalProperty( + "X-Custom-Header", + JsonValue.from("value"), + ) + .build() + ) + .skipApiKeyFallback(true) + .build() + ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) From 2c03d75635f80c00a0ef32930ca4ce0d7a4b76da Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 23:32:49 +0000 Subject: [PATCH 144/164] feat: [STG-1798] feat: support Browserbase verified sessions --- .stats.yml | 6 +- .../api/models/sessions/SessionStartParams.kt | 306 +++++++++++++++++- .../models/sessions/SessionStartParamsTest.kt | 32 ++ .../api/services/ErrorHandlingTest.kt | 153 +++++++++ .../api/services/ServiceParamsTest.kt | 9 + .../services/async/SessionServiceAsyncTest.kt | 9 + .../services/blocking/SessionServiceTest.kt | 9 + 7 files changed, 520 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index f1d6429..6bde59e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-7773ef4ca29c983daafb787ee918cfa6b5b12c5bbdc088308653f2737c26e51f.yml -openapi_spec_hash: 47fc8f2540be0b6374e4230c021072d9 -config_hash: 0cc516caf1432087f40654336e0fa8cd +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a8db51c6460b3daff67b35262517848a0d4e783c6805c2edd531b155a5db71dd.yml +openapi_spec_hash: c6e7127f211f946673d6389e1d8db1ba +config_hash: a962ae71493deb11a1c903256fb25386 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 3b2547c..a2fba41 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -3747,12 +3747,16 @@ private constructor( private constructor( private val advancedStealth: JsonField, private val blockAds: JsonField, + private val captchaImageSelector: JsonField, + private val captchaInputSelector: JsonField, private val context: JsonField, private val extensionId: JsonField, private val fingerprint: JsonField, private val logSession: JsonField, + private val os: JsonField, private val recordSession: JsonField, private val solveCaptchas: JsonField, + private val verified: JsonField, private val viewport: JsonField, private val additionalProperties: MutableMap, ) { @@ -3765,6 +3769,12 @@ private constructor( @JsonProperty("blockAds") @ExcludeMissing blockAds: JsonField = JsonMissing.of(), + @JsonProperty("captchaImageSelector") + @ExcludeMissing + captchaImageSelector: JsonField = JsonMissing.of(), + @JsonProperty("captchaInputSelector") + @ExcludeMissing + captchaInputSelector: JsonField = JsonMissing.of(), @JsonProperty("context") @ExcludeMissing context: JsonField = JsonMissing.of(), @@ -3777,24 +3787,32 @@ private constructor( @JsonProperty("logSession") @ExcludeMissing logSession: JsonField = JsonMissing.of(), + @JsonProperty("os") @ExcludeMissing os: JsonField = JsonMissing.of(), @JsonProperty("recordSession") @ExcludeMissing recordSession: JsonField = JsonMissing.of(), @JsonProperty("solveCaptchas") @ExcludeMissing solveCaptchas: JsonField = JsonMissing.of(), + @JsonProperty("verified") + @ExcludeMissing + verified: JsonField = JsonMissing.of(), @JsonProperty("viewport") @ExcludeMissing viewport: JsonField = JsonMissing.of(), ) : this( advancedStealth, blockAds, + captchaImageSelector, + captchaInputSelector, context, extensionId, fingerprint, logSession, + os, recordSession, solveCaptchas, + verified, viewport, mutableMapOf(), ) @@ -3812,6 +3830,20 @@ private constructor( */ fun blockAds(): Optional = blockAds.getOptional("blockAds") + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun captchaImageSelector(): Optional = + captchaImageSelector.getOptional("captchaImageSelector") + + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun captchaInputSelector(): Optional = + captchaInputSelector.getOptional("captchaInputSelector") + /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. * if the server responded with an unexpected value). @@ -3836,6 +3868,12 @@ private constructor( */ fun logSession(): Optional = logSession.getOptional("logSession") + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun os(): Optional = os.getOptional("os") + /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. * if the server responded with an unexpected value). @@ -3848,6 +3886,12 @@ private constructor( */ fun solveCaptchas(): Optional = solveCaptchas.getOptional("solveCaptchas") + /** + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. + * if the server responded with an unexpected value). + */ + fun verified(): Optional = verified.getOptional("verified") + /** * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. * if the server responded with an unexpected value). @@ -3872,6 +3916,26 @@ private constructor( */ @JsonProperty("blockAds") @ExcludeMissing fun _blockAds(): JsonField = blockAds + /** + * Returns the raw JSON value of [captchaImageSelector]. + * + * Unlike [captchaImageSelector], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("captchaImageSelector") + @ExcludeMissing + fun _captchaImageSelector(): JsonField = captchaImageSelector + + /** + * Returns the raw JSON value of [captchaInputSelector]. + * + * Unlike [captchaInputSelector], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("captchaInputSelector") + @ExcludeMissing + fun _captchaInputSelector(): JsonField = captchaInputSelector + /** * Returns the raw JSON value of [context]. * @@ -3909,6 +3973,13 @@ private constructor( @ExcludeMissing fun _logSession(): JsonField = logSession + /** + * Returns the raw JSON value of [os]. + * + * Unlike [os], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("os") @ExcludeMissing fun _os(): JsonField = os + /** * Returns the raw JSON value of [recordSession]. * @@ -3929,6 +4000,14 @@ private constructor( @ExcludeMissing fun _solveCaptchas(): JsonField = solveCaptchas + /** + * Returns the raw JSON value of [verified]. + * + * Unlike [verified], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("verified") @ExcludeMissing fun _verified(): JsonField = verified + /** * Returns the raw JSON value of [viewport]. * @@ -3962,12 +4041,16 @@ private constructor( private var advancedStealth: JsonField = JsonMissing.of() private var blockAds: JsonField = JsonMissing.of() + private var captchaImageSelector: JsonField = JsonMissing.of() + private var captchaInputSelector: JsonField = JsonMissing.of() private var context: JsonField = JsonMissing.of() private var extensionId: JsonField = JsonMissing.of() private var fingerprint: JsonField = JsonMissing.of() private var logSession: JsonField = JsonMissing.of() + private var os: JsonField = JsonMissing.of() private var recordSession: JsonField = JsonMissing.of() private var solveCaptchas: JsonField = JsonMissing.of() + private var verified: JsonField = JsonMissing.of() private var viewport: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -3975,12 +4058,16 @@ private constructor( internal fun from(browserSettings: BrowserSettings) = apply { advancedStealth = browserSettings.advancedStealth blockAds = browserSettings.blockAds + captchaImageSelector = browserSettings.captchaImageSelector + captchaInputSelector = browserSettings.captchaInputSelector context = browserSettings.context extensionId = browserSettings.extensionId fingerprint = browserSettings.fingerprint logSession = browserSettings.logSession + os = browserSettings.os recordSession = browserSettings.recordSession solveCaptchas = browserSettings.solveCaptchas + verified = browserSettings.verified viewport = browserSettings.viewport additionalProperties = browserSettings.additionalProperties.toMutableMap() } @@ -4010,6 +4097,34 @@ private constructor( */ fun blockAds(blockAds: JsonField) = apply { this.blockAds = blockAds } + fun captchaImageSelector(captchaImageSelector: String) = + captchaImageSelector(JsonField.of(captchaImageSelector)) + + /** + * Sets [Builder.captchaImageSelector] to an arbitrary JSON value. + * + * You should usually call [Builder.captchaImageSelector] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun captchaImageSelector(captchaImageSelector: JsonField) = apply { + this.captchaImageSelector = captchaImageSelector + } + + fun captchaInputSelector(captchaInputSelector: String) = + captchaInputSelector(JsonField.of(captchaInputSelector)) + + /** + * Sets [Builder.captchaInputSelector] to an arbitrary JSON value. + * + * You should usually call [Builder.captchaInputSelector] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun captchaInputSelector(captchaInputSelector: JsonField) = apply { + this.captchaInputSelector = captchaInputSelector + } + fun context(context: Context) = context(JsonField.of(context)) /** @@ -4060,6 +4175,17 @@ private constructor( this.logSession = logSession } + fun os(os: Os) = os(JsonField.of(os)) + + /** + * Sets [Builder.os] to an arbitrary JSON value. + * + * You should usually call [Builder.os] with a well-typed [Os] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun os(os: JsonField) = apply { this.os = os } + fun recordSession(recordSession: Boolean) = recordSession(JsonField.of(recordSession)) @@ -4088,6 +4214,17 @@ private constructor( this.solveCaptchas = solveCaptchas } + fun verified(verified: Boolean) = verified(JsonField.of(verified)) + + /** + * Sets [Builder.verified] to an arbitrary JSON value. + * + * You should usually call [Builder.verified] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun verified(verified: JsonField) = apply { this.verified = verified } + fun viewport(viewport: Viewport) = viewport(JsonField.of(viewport)) /** @@ -4130,12 +4267,16 @@ private constructor( BrowserSettings( advancedStealth, blockAds, + captchaImageSelector, + captchaInputSelector, context, extensionId, fingerprint, logSession, + os, recordSession, solveCaptchas, + verified, viewport, additionalProperties.toMutableMap(), ) @@ -4150,12 +4291,16 @@ private constructor( advancedStealth() blockAds() + captchaImageSelector() + captchaInputSelector() context().ifPresent { it.validate() } extensionId() fingerprint().ifPresent { it.validate() } logSession() + os().ifPresent { it.validate() } recordSession() solveCaptchas() + verified() viewport().ifPresent { it.validate() } validated = true } @@ -4178,12 +4323,16 @@ private constructor( internal fun validity(): Int = (if (advancedStealth.asKnown().isPresent) 1 else 0) + (if (blockAds.asKnown().isPresent) 1 else 0) + + (if (captchaImageSelector.asKnown().isPresent) 1 else 0) + + (if (captchaInputSelector.asKnown().isPresent) 1 else 0) + (context.asKnown().getOrNull()?.validity() ?: 0) + (if (extensionId.asKnown().isPresent) 1 else 0) + (fingerprint.asKnown().getOrNull()?.validity() ?: 0) + (if (logSession.asKnown().isPresent) 1 else 0) + + (os.asKnown().getOrNull()?.validity() ?: 0) + (if (recordSession.asKnown().isPresent) 1 else 0) + (if (solveCaptchas.asKnown().isPresent) 1 else 0) + + (if (verified.asKnown().isPresent) 1 else 0) + (viewport.asKnown().getOrNull()?.validity() ?: 0) class Context @@ -5651,6 +5800,153 @@ private constructor( "Fingerprint{browsers=$browsers, devices=$devices, httpVersion=$httpVersion, locales=$locales, operatingSystems=$operatingSystems, screen=$screen, additionalProperties=$additionalProperties}" } + class Os @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val WINDOWS = of("windows") + + @JvmField val MAC = of("mac") + + @JvmField val LINUX = of("linux") + + @JvmField val MOBILE = of("mobile") + + @JvmField val TABLET = of("tablet") + + @JvmStatic fun of(value: String) = Os(JsonField.of(value)) + } + + /** An enum containing [Os]'s known values. */ + enum class Known { + WINDOWS, + MAC, + LINUX, + MOBILE, + TABLET, + } + + /** + * An enum containing [Os]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Os] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + WINDOWS, + MAC, + LINUX, + MOBILE, + TABLET, + /** + * An enum member indicating that [Os] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + WINDOWS -> Value.WINDOWS + MAC -> Value.MAC + LINUX -> Value.LINUX + MOBILE -> Value.MOBILE + TABLET -> Value.TABLET + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws StagehandInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + WINDOWS -> Known.WINDOWS + MAC -> Known.MAC + LINUX -> Known.LINUX + MOBILE -> Known.MOBILE + TABLET -> Known.TABLET + else -> throw StagehandInvalidDataException("Unknown Os: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws StagehandInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + StagehandInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Os = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Os && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + class Viewport @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( @@ -5842,12 +6138,16 @@ private constructor( return other is BrowserSettings && advancedStealth == other.advancedStealth && blockAds == other.blockAds && + captchaImageSelector == other.captchaImageSelector && + captchaInputSelector == other.captchaInputSelector && context == other.context && extensionId == other.extensionId && fingerprint == other.fingerprint && logSession == other.logSession && + os == other.os && recordSession == other.recordSession && solveCaptchas == other.solveCaptchas && + verified == other.verified && viewport == other.viewport && additionalProperties == other.additionalProperties } @@ -5856,12 +6156,16 @@ private constructor( Objects.hash( advancedStealth, blockAds, + captchaImageSelector, + captchaInputSelector, context, extensionId, fingerprint, logSession, + os, recordSession, solveCaptchas, + verified, viewport, additionalProperties, ) @@ -5870,7 +6174,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "BrowserSettings{advancedStealth=$advancedStealth, blockAds=$blockAds, context=$context, extensionId=$extensionId, fingerprint=$fingerprint, logSession=$logSession, recordSession=$recordSession, solveCaptchas=$solveCaptchas, viewport=$viewport, additionalProperties=$additionalProperties}" + "BrowserSettings{advancedStealth=$advancedStealth, blockAds=$blockAds, captchaImageSelector=$captchaImageSelector, captchaInputSelector=$captchaInputSelector, context=$context, extensionId=$extensionId, fingerprint=$fingerprint, logSession=$logSession, os=$os, recordSession=$recordSession, solveCaptchas=$solveCaptchas, verified=$verified, viewport=$viewport, additionalProperties=$additionalProperties}" } @JsonDeserialize(using = Proxies.Deserializer::class) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index eef7a55..0d05eca 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -67,6 +67,8 @@ internal class SessionStartParamsTest { SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings.builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings .Context @@ -124,8 +126,13 @@ internal class SessionStartParamsTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings.Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings .Viewport @@ -240,6 +247,8 @@ internal class SessionStartParamsTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -299,8 +308,15 @@ internal class SessionStartParamsTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -429,6 +445,8 @@ internal class SessionStartParamsTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -488,8 +506,15 @@ internal class SessionStartParamsTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -602,6 +627,8 @@ internal class SessionStartParamsTest { SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings.builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings .Context @@ -659,8 +686,13 @@ internal class SessionStartParamsTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings.Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams.BrowserSettings .Viewport diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index 194631c..fce6e48 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -136,6 +136,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -200,8 +202,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -349,6 +358,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -413,8 +424,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -562,6 +580,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -626,8 +646,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -775,6 +802,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -839,8 +868,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -988,6 +1024,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1052,8 +1090,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1201,6 +1246,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1265,8 +1312,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1414,6 +1468,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1478,8 +1534,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1627,6 +1690,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1691,8 +1756,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1840,6 +1912,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -1904,8 +1978,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2053,6 +2134,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2117,8 +2200,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2266,6 +2356,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2330,8 +2422,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2479,6 +2578,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2543,8 +2644,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2692,6 +2800,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2756,8 +2866,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2905,6 +3022,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -2969,8 +3088,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -3118,6 +3244,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -3182,8 +3310,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -3331,6 +3466,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -3395,8 +3532,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -3542,6 +3686,8 @@ internal class ErrorHandlingTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -3606,8 +3752,15 @@ internal class ErrorHandlingTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index 233fdfd..b67f63c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -104,6 +104,8 @@ internal class ServiceParamsTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -163,8 +165,15 @@ internal class ServiceParamsTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 0d1d6b0..78f3def 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -736,6 +736,8 @@ internal class SessionServiceAsyncTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -795,8 +797,15 @@ internal class SessionServiceAsyncTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index cf8b728..7d7349d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -729,6 +729,8 @@ internal class SessionServiceTest { .builder() .advancedStealth(true) .blockAds(true) + .captchaImageSelector("captchaImageSelector") + .captchaInputSelector("captchaInputSelector") .context( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings @@ -788,8 +790,15 @@ internal class SessionServiceTest { .build() ) .logSession(true) + .os( + SessionStartParams.BrowserbaseSessionCreateParams + .BrowserSettings + .Os + .WINDOWS + ) .recordSession(true) .solveCaptchas(true) + .verified(true) .viewport( SessionStartParams.BrowserbaseSessionCreateParams .BrowserSettings From 75c06f5500e7dc56edeb95ea898518b25e6f4c00 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:32:12 +0000 Subject: [PATCH 145/164] feat: Revert "[STG-1573] Add providerOptions for extensible model auth (#1822)" --- .stats.yml | 4 +- .../api/models/sessions/ModelConfig.kt | 1987 +------- .../models/sessions/SessionExecuteParams.kt | 97 +- .../api/models/sessions/SessionStartParams.kt | 4089 +---------------- .../api/models/sessions/StreamEvent.kt | 4 +- .../api/models/sessions/ModelConfigTest.kt | 33 +- .../models/sessions/SessionActParamsTest.kt | 54 +- .../sessions/SessionExecuteParamsTest.kt | 116 +- .../sessions/SessionExtractParamsTest.kt | 54 +- .../sessions/SessionObserveParamsTest.kt | 54 +- .../models/sessions/SessionStartParamsTest.kt | 87 - .../api/services/ErrorHandlingTest.kt | 459 -- .../api/services/ServiceParamsTest.kt | 35 +- .../services/async/SessionServiceAsyncTest.kt | 171 +- .../services/blocking/SessionServiceTest.kt | 171 +- 15 files changed, 208 insertions(+), 7207 deletions(-) diff --git a/.stats.yml b/.stats.yml index 6bde59e..d8428d4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-a8db51c6460b3daff67b35262517848a0d4e783c6805c2edd531b155a5db71dd.yml -openapi_spec_hash: c6e7127f211f946673d6389e1d8db1ba +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1c6caa2891a7f3bdfc0caab143f285badc9145220c9b29cd5e4cf1a9b3ac11cf.yml +openapi_spec_hash: 28c4b734a5309067c39bb4c4b709b9ab config_hash: a962ae71493deb11a1c903256fb25386 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index c397bfa..4e46131 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -2,29 +2,18 @@ package com.browserbase.api.models.sessions -import com.browserbase.api.core.BaseDeserializer -import com.browserbase.api.core.BaseSerializer import com.browserbase.api.core.Enum import com.browserbase.api.core.ExcludeMissing import com.browserbase.api.core.JsonField import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue -import com.browserbase.api.core.allMaxBy import com.browserbase.api.core.checkRequired -import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.ObjectCodec -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import com.fasterxml.jackson.databind.annotation.JsonSerialize -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import java.util.Collections import java.util.Objects import java.util.Optional @@ -38,8 +27,6 @@ private constructor( private val baseUrl: JsonField, private val headers: JsonField, private val provider: JsonField, - private val providerOptions: JsonField, - private val skipApiKeyFallback: JsonField, private val additionalProperties: MutableMap, ) { @@ -50,22 +37,7 @@ private constructor( @JsonProperty("baseURL") @ExcludeMissing baseUrl: JsonField = JsonMissing.of(), @JsonProperty("headers") @ExcludeMissing headers: JsonField = JsonMissing.of(), @JsonProperty("provider") @ExcludeMissing provider: JsonField = JsonMissing.of(), - @JsonProperty("providerOptions") - @ExcludeMissing - providerOptions: JsonField = JsonMissing.of(), - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - skipApiKeyFallback: JsonField = JsonMissing.of(), - ) : this( - modelName, - apiKey, - baseUrl, - headers, - provider, - providerOptions, - skipApiKeyFallback, - mutableMapOf(), - ) + ) : this(modelName, apiKey, baseUrl, headers, provider, mutableMapOf()) /** * Model name string with provider prefix (e.g., 'openai/gpt-5-nano') @@ -92,7 +64,7 @@ private constructor( fun baseUrl(): Optional = baseUrl.getOptional("baseURL") /** - * Custom headers for the model provider + * Custom headers sent with every request to the model provider * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). @@ -107,27 +79,6 @@ private constructor( */ fun provider(): Optional = provider.getOptional("provider") - /** - * Provider-specific options passed through to the AI SDK provider constructor. For Bedrock: { - * region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { project, location, - * googleAuthOptions }. - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun providerOptions(): Optional = - providerOptions.getOptional("providerOptions") - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this when - * auth is carried through providerOptions instead of an API key. - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun skipApiKeyFallback(): Optional = - skipApiKeyFallback.getOptional("skipApiKeyFallback") - /** * Returns the raw JSON value of [modelName]. * @@ -163,25 +114,6 @@ private constructor( */ @JsonProperty("provider") @ExcludeMissing fun _provider(): JsonField = provider - /** - * Returns the raw JSON value of [providerOptions]. - * - * Unlike [providerOptions], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("providerOptions") - @ExcludeMissing - fun _providerOptions(): JsonField = providerOptions - - /** - * Returns the raw JSON value of [skipApiKeyFallback]. - * - * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -215,8 +147,6 @@ private constructor( private var baseUrl: JsonField = JsonMissing.of() private var headers: JsonField = JsonMissing.of() private var provider: JsonField = JsonMissing.of() - private var providerOptions: JsonField = JsonMissing.of() - private var skipApiKeyFallback: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -226,8 +156,6 @@ private constructor( baseUrl = modelConfig.baseUrl headers = modelConfig.headers provider = modelConfig.provider - providerOptions = modelConfig.providerOptions - skipApiKeyFallback = modelConfig.skipApiKeyFallback additionalProperties = modelConfig.additionalProperties.toMutableMap() } @@ -265,7 +193,7 @@ private constructor( */ fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - /** Custom headers for the model provider */ + /** Custom headers sent with every request to the model provider */ fun headers(headers: Headers) = headers(JsonField.of(headers)) /** @@ -288,64 +216,6 @@ private constructor( */ fun provider(provider: JsonField) = apply { this.provider = provider } - /** - * Provider-specific options passed through to the AI SDK provider constructor. For Bedrock: - * { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { project, location, - * googleAuthOptions }. - */ - fun providerOptions(providerOptions: ProviderOptions) = - providerOptions(JsonField.of(providerOptions)) - - /** - * Sets [Builder.providerOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.providerOptions] with a well-typed [ProviderOptions] - * value instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun providerOptions(providerOptions: JsonField) = apply { - this.providerOptions = providerOptions - } - - /** - * Alias for calling [providerOptions] with - * `ProviderOptions.ofBedrockApiKey(bedrockApiKey)`. - */ - fun providerOptions(bedrockApiKey: ProviderOptions.BedrockApiKeyProviderOptions) = - providerOptions(ProviderOptions.ofBedrockApiKey(bedrockApiKey)) - - /** - * Alias for calling [providerOptions] with - * `ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. - */ - fun providerOptions( - bedrockAwsCredentials: ProviderOptions.BedrockAwsCredentialsProviderOptions - ) = providerOptions(ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)) - - /** - * Alias for calling [providerOptions] with `ProviderOptions.ofGoogleVertex(googleVertex)`. - */ - fun providerOptions(googleVertex: ProviderOptions.GoogleVertexProviderOptions) = - providerOptions(ProviderOptions.ofGoogleVertex(googleVertex)) - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this when - * auth is carried through providerOptions instead of an API key. - */ - fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = - skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) - - /** - * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. - * - * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { - this.skipApiKeyFallback = skipApiKeyFallback - } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -384,8 +254,6 @@ private constructor( baseUrl, headers, provider, - providerOptions, - skipApiKeyFallback, additionalProperties.toMutableMap(), ) } @@ -402,8 +270,6 @@ private constructor( baseUrl() headers().ifPresent { it.validate() } provider().ifPresent { it.validate() } - providerOptions().ifPresent { it.validate() } - skipApiKeyFallback() validated = true } @@ -426,11 +292,9 @@ private constructor( (if (apiKey.asKnown().isPresent) 1 else 0) + (if (baseUrl.asKnown().isPresent) 1 else 0) + (headers.asKnown().getOrNull()?.validity() ?: 0) + - (provider.asKnown().getOrNull()?.validity() ?: 0) + - (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + - (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) + (provider.asKnown().getOrNull()?.validity() ?: 0) - /** Custom headers for the model provider */ + /** Custom headers sent with every request to the model provider */ class Headers @JsonCreator private constructor( @@ -676,1832 +540,6 @@ private constructor( override fun toString() = value.toString() } - /** - * Provider-specific options passed through to the AI SDK provider constructor. For Bedrock: { - * region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { project, location, - * googleAuthOptions }. - */ - @JsonDeserialize(using = ProviderOptions.Deserializer::class) - @JsonSerialize(using = ProviderOptions.Serializer::class) - class ProviderOptions - private constructor( - private val bedrockApiKey: BedrockApiKeyProviderOptions? = null, - private val bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions? = null, - private val googleVertex: GoogleVertexProviderOptions? = null, - private val _json: JsonValue? = null, - ) { - - fun bedrockApiKey(): Optional = - Optional.ofNullable(bedrockApiKey) - - fun bedrockAwsCredentials(): Optional = - Optional.ofNullable(bedrockAwsCredentials) - - fun googleVertex(): Optional = - Optional.ofNullable(googleVertex) - - fun isBedrockApiKey(): Boolean = bedrockApiKey != null - - fun isBedrockAwsCredentials(): Boolean = bedrockAwsCredentials != null - - fun isGoogleVertex(): Boolean = googleVertex != null - - fun asBedrockApiKey(): BedrockApiKeyProviderOptions = - bedrockApiKey.getOrThrow("bedrockApiKey") - - fun asBedrockAwsCredentials(): BedrockAwsCredentialsProviderOptions = - bedrockAwsCredentials.getOrThrow("bedrockAwsCredentials") - - fun asGoogleVertex(): GoogleVertexProviderOptions = googleVertex.getOrThrow("googleVertex") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - bedrockApiKey != null -> visitor.visitBedrockApiKey(bedrockApiKey) - bedrockAwsCredentials != null -> - visitor.visitBedrockAwsCredentials(bedrockAwsCredentials) - googleVertex != null -> visitor.visitGoogleVertex(googleVertex) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): ProviderOptions = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) { - bedrockApiKey.validate() - } - - override fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ) { - bedrockAwsCredentials.validate() - } - - override fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions) { - googleVertex.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) = - bedrockApiKey.validity() - - override fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ) = bedrockAwsCredentials.validity() - - override fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions) = - googleVertex.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProviderOptions && - bedrockApiKey == other.bedrockApiKey && - bedrockAwsCredentials == other.bedrockAwsCredentials && - googleVertex == other.googleVertex - } - - override fun hashCode(): Int = - Objects.hash(bedrockApiKey, bedrockAwsCredentials, googleVertex) - - override fun toString(): String = - when { - bedrockApiKey != null -> "ProviderOptions{bedrockApiKey=$bedrockApiKey}" - bedrockAwsCredentials != null -> - "ProviderOptions{bedrockAwsCredentials=$bedrockAwsCredentials}" - googleVertex != null -> "ProviderOptions{googleVertex=$googleVertex}" - _json != null -> "ProviderOptions{_unknown=$_json}" - else -> throw IllegalStateException("Invalid ProviderOptions") - } - - companion object { - - @JvmStatic - fun ofBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) = - ProviderOptions(bedrockApiKey = bedrockApiKey) - - @JvmStatic - fun ofBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ) = ProviderOptions(bedrockAwsCredentials = bedrockAwsCredentials) - - @JvmStatic - fun ofGoogleVertex(googleVertex: GoogleVertexProviderOptions) = - ProviderOptions(googleVertex = googleVertex) - } - - /** - * An interface that defines how to map each variant of [ProviderOptions] to a value of type - * [T]. - */ - interface Visitor { - - fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions): T - - fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ): T - - fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions): T - - /** - * Maps an unknown variant of [ProviderOptions] to a value of type [T]. - * - * An instance of [ProviderOptions] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, if the SDK - * is on an older version than the API, then the API may respond with new variants that - * the SDK is unaware of. - * - * @throws StagehandInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown ProviderOptions: $json") - } - } - - internal class Deserializer : BaseDeserializer(ProviderOptions::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): ProviderOptions { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { ProviderOptions(bedrockApiKey = it, _json = json) }, - tryDeserialize( - node, - jacksonTypeRef(), - ) - ?.let { ProviderOptions(bedrockAwsCredentials = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef()) - ?.let { ProviderOptions(googleVertex = it, _json = json) }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible with - // all the possible variants (e.g. deserializing from boolean). - 0 -> ProviderOptions(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the first - // completely valid match, or simply the first match if none are completely - // valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(ProviderOptions::class) { - - override fun serialize( - value: ProviderOptions, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.bedrockApiKey != null -> generator.writeObject(value.bedrockApiKey) - value.bedrockAwsCredentials != null -> - generator.writeObject(value.bedrockAwsCredentials) - value.googleVertex != null -> generator.writeObject(value.googleVertex) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid ProviderOptions") - } - } - } - - class BedrockApiKeyProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val region: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("region") @ExcludeMissing region: JsonField = JsonMissing.of() - ) : this(region, mutableMapOf()) - - /** - * AWS region for Amazon Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun region(): String = region.getRequired("region") - - /** - * Returns the raw JSON value of [region]. - * - * Unlike [region], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [BedrockApiKeyProviderOptions]. - * - * The following fields are required: - * ```java - * .region() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [BedrockApiKeyProviderOptions]. */ - class Builder internal constructor() { - - private var region: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(bedrockApiKeyProviderOptions: BedrockApiKeyProviderOptions) = - apply { - region = bedrockApiKeyProviderOptions.region - additionalProperties = - bedrockApiKeyProviderOptions.additionalProperties.toMutableMap() - } - - /** AWS region for Amazon Bedrock */ - fun region(region: String) = region(JsonField.of(region)) - - /** - * Sets [Builder.region] to an arbitrary JSON value. - * - * You should usually call [Builder.region] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun region(region: JsonField) = apply { this.region = region } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [BedrockApiKeyProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .region() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): BedrockApiKeyProviderOptions = - BedrockApiKeyProviderOptions( - checkRequired("region", region), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): BedrockApiKeyProviderOptions = apply { - if (validated) { - return@apply - } - - region() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = (if (region.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BedrockApiKeyProviderOptions && - region == other.region && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(region, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "BedrockApiKeyProviderOptions{region=$region, additionalProperties=$additionalProperties}" - } - - class BedrockAwsCredentialsProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val accessKeyId: JsonField, - private val region: JsonField, - private val secretAccessKey: JsonField, - private val sessionToken: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("accessKeyId") - @ExcludeMissing - accessKeyId: JsonField = JsonMissing.of(), - @JsonProperty("region") - @ExcludeMissing - region: JsonField = JsonMissing.of(), - @JsonProperty("secretAccessKey") - @ExcludeMissing - secretAccessKey: JsonField = JsonMissing.of(), - @JsonProperty("sessionToken") - @ExcludeMissing - sessionToken: JsonField = JsonMissing.of(), - ) : this(accessKeyId, region, secretAccessKey, sessionToken, mutableMapOf()) - - /** - * AWS access key ID for Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun accessKeyId(): String = accessKeyId.getRequired("accessKeyId") - - /** - * AWS region for Amazon Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun region(): String = region.getRequired("region") - - /** - * AWS secret access key for Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun secretAccessKey(): String = secretAccessKey.getRequired("secretAccessKey") - - /** - * Optional AWS session token for temporary credentials - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun sessionToken(): Optional = sessionToken.getOptional("sessionToken") - - /** - * Returns the raw JSON value of [accessKeyId]. - * - * Unlike [accessKeyId], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("accessKeyId") - @ExcludeMissing - fun _accessKeyId(): JsonField = accessKeyId - - /** - * Returns the raw JSON value of [region]. - * - * Unlike [region], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region - - /** - * Returns the raw JSON value of [secretAccessKey]. - * - * Unlike [secretAccessKey], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("secretAccessKey") - @ExcludeMissing - fun _secretAccessKey(): JsonField = secretAccessKey - - /** - * Returns the raw JSON value of [sessionToken]. - * - * Unlike [sessionToken], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("sessionToken") - @ExcludeMissing - fun _sessionToken(): JsonField = sessionToken - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [BedrockAwsCredentialsProviderOptions]. - * - * The following fields are required: - * ```java - * .accessKeyId() - * .region() - * .secretAccessKey() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [BedrockAwsCredentialsProviderOptions]. */ - class Builder internal constructor() { - - private var accessKeyId: JsonField? = null - private var region: JsonField? = null - private var secretAccessKey: JsonField? = null - private var sessionToken: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from( - bedrockAwsCredentialsProviderOptions: BedrockAwsCredentialsProviderOptions - ) = apply { - accessKeyId = bedrockAwsCredentialsProviderOptions.accessKeyId - region = bedrockAwsCredentialsProviderOptions.region - secretAccessKey = bedrockAwsCredentialsProviderOptions.secretAccessKey - sessionToken = bedrockAwsCredentialsProviderOptions.sessionToken - additionalProperties = - bedrockAwsCredentialsProviderOptions.additionalProperties.toMutableMap() - } - - /** AWS access key ID for Bedrock */ - fun accessKeyId(accessKeyId: String) = accessKeyId(JsonField.of(accessKeyId)) - - /** - * Sets [Builder.accessKeyId] to an arbitrary JSON value. - * - * You should usually call [Builder.accessKeyId] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun accessKeyId(accessKeyId: JsonField) = apply { - this.accessKeyId = accessKeyId - } - - /** AWS region for Amazon Bedrock */ - fun region(region: String) = region(JsonField.of(region)) - - /** - * Sets [Builder.region] to an arbitrary JSON value. - * - * You should usually call [Builder.region] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun region(region: JsonField) = apply { this.region = region } - - /** AWS secret access key for Bedrock */ - fun secretAccessKey(secretAccessKey: String) = - secretAccessKey(JsonField.of(secretAccessKey)) - - /** - * Sets [Builder.secretAccessKey] to an arbitrary JSON value. - * - * You should usually call [Builder.secretAccessKey] with a well-typed [String] - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. - */ - fun secretAccessKey(secretAccessKey: JsonField) = apply { - this.secretAccessKey = secretAccessKey - } - - /** Optional AWS session token for temporary credentials */ - fun sessionToken(sessionToken: String) = sessionToken(JsonField.of(sessionToken)) - - /** - * Sets [Builder.sessionToken] to an arbitrary JSON value. - * - * You should usually call [Builder.sessionToken] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun sessionToken(sessionToken: JsonField) = apply { - this.sessionToken = sessionToken - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [BedrockAwsCredentialsProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .accessKeyId() - * .region() - * .secretAccessKey() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): BedrockAwsCredentialsProviderOptions = - BedrockAwsCredentialsProviderOptions( - checkRequired("accessKeyId", accessKeyId), - checkRequired("region", region), - checkRequired("secretAccessKey", secretAccessKey), - sessionToken, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): BedrockAwsCredentialsProviderOptions = apply { - if (validated) { - return@apply - } - - accessKeyId() - region() - secretAccessKey() - sessionToken() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (accessKeyId.asKnown().isPresent) 1 else 0) + - (if (region.asKnown().isPresent) 1 else 0) + - (if (secretAccessKey.asKnown().isPresent) 1 else 0) + - (if (sessionToken.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BedrockAwsCredentialsProviderOptions && - accessKeyId == other.accessKeyId && - region == other.region && - secretAccessKey == other.secretAccessKey && - sessionToken == other.sessionToken && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - accessKeyId, - region, - secretAccessKey, - sessionToken, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "BedrockAwsCredentialsProviderOptions{accessKeyId=$accessKeyId, region=$region, secretAccessKey=$secretAccessKey, sessionToken=$sessionToken, additionalProperties=$additionalProperties}" - } - - class GoogleVertexProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val googleAuthOptions: JsonField, - private val headers: JsonField, - private val location: JsonField, - private val project: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("googleAuthOptions") - @ExcludeMissing - googleAuthOptions: JsonField = JsonMissing.of(), - @JsonProperty("headers") - @ExcludeMissing - headers: JsonField = JsonMissing.of(), - @JsonProperty("location") - @ExcludeMissing - location: JsonField = JsonMissing.of(), - @JsonProperty("project") - @ExcludeMissing - project: JsonField = JsonMissing.of(), - ) : this(googleAuthOptions, headers, location, project, mutableMapOf()) - - /** - * Optional Google auth options for Vertex AI - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun googleAuthOptions(): Optional = - googleAuthOptions.getOptional("googleAuthOptions") - - /** - * Custom headers for Vertex AI requests - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun headers(): Optional = headers.getOptional("headers") - - /** - * Google Cloud location for Vertex AI - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun location(): Optional = location.getOptional("location") - - /** - * Google Cloud project ID for Vertex AI - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun project(): Optional = project.getOptional("project") - - /** - * Returns the raw JSON value of [googleAuthOptions]. - * - * Unlike [googleAuthOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("googleAuthOptions") - @ExcludeMissing - fun _googleAuthOptions(): JsonField = googleAuthOptions - - /** - * Returns the raw JSON value of [headers]. - * - * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers - - /** - * Returns the raw JSON value of [location]. - * - * Unlike [location], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("location") @ExcludeMissing fun _location(): JsonField = location - - /** - * Returns the raw JSON value of [project]. - * - * Unlike [project], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("project") @ExcludeMissing fun _project(): JsonField = project - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GoogleVertexProviderOptions]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GoogleVertexProviderOptions]. */ - class Builder internal constructor() { - - private var googleAuthOptions: JsonField = JsonMissing.of() - private var headers: JsonField = JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var project: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(googleVertexProviderOptions: GoogleVertexProviderOptions) = - apply { - googleAuthOptions = googleVertexProviderOptions.googleAuthOptions - headers = googleVertexProviderOptions.headers - location = googleVertexProviderOptions.location - project = googleVertexProviderOptions.project - additionalProperties = - googleVertexProviderOptions.additionalProperties.toMutableMap() - } - - /** Optional Google auth options for Vertex AI */ - fun googleAuthOptions(googleAuthOptions: GoogleAuthOptions) = - googleAuthOptions(JsonField.of(googleAuthOptions)) - - /** - * Sets [Builder.googleAuthOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.googleAuthOptions] with a well-typed - * [GoogleAuthOptions] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun googleAuthOptions(googleAuthOptions: JsonField) = apply { - this.googleAuthOptions = googleAuthOptions - } - - /** Custom headers for Vertex AI requests */ - fun headers(headers: Headers) = headers(JsonField.of(headers)) - - /** - * Sets [Builder.headers] to an arbitrary JSON value. - * - * You should usually call [Builder.headers] with a well-typed [Headers] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun headers(headers: JsonField) = apply { this.headers = headers } - - /** Google Cloud location for Vertex AI */ - fun location(location: String) = location(JsonField.of(location)) - - /** - * Sets [Builder.location] to an arbitrary JSON value. - * - * You should usually call [Builder.location] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun location(location: JsonField) = apply { this.location = location } - - /** Google Cloud project ID for Vertex AI */ - fun project(project: String) = project(JsonField.of(project)) - - /** - * Sets [Builder.project] to an arbitrary JSON value. - * - * You should usually call [Builder.project] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun project(project: JsonField) = apply { this.project = project } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GoogleVertexProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): GoogleVertexProviderOptions = - GoogleVertexProviderOptions( - googleAuthOptions, - headers, - location, - project, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): GoogleVertexProviderOptions = apply { - if (validated) { - return@apply - } - - googleAuthOptions().ifPresent { it.validate() } - headers().ifPresent { it.validate() } - location() - project() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (googleAuthOptions.asKnown().getOrNull()?.validity() ?: 0) + - (headers.asKnown().getOrNull()?.validity() ?: 0) + - (if (location.asKnown().isPresent) 1 else 0) + - (if (project.asKnown().isPresent) 1 else 0) - - /** Optional Google auth options for Vertex AI */ - class GoogleAuthOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val credentials: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("credentials") - @ExcludeMissing - credentials: JsonField = JsonMissing.of() - ) : this(credentials, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun credentials(): Optional = credentials.getOptional("credentials") - - /** - * Returns the raw JSON value of [credentials]. - * - * Unlike [credentials], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("credentials") - @ExcludeMissing - fun _credentials(): JsonField = credentials - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GoogleAuthOptions]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GoogleAuthOptions]. */ - class Builder internal constructor() { - - private var credentials: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(googleAuthOptions: GoogleAuthOptions) = apply { - credentials = googleAuthOptions.credentials - additionalProperties = googleAuthOptions.additionalProperties.toMutableMap() - } - - fun credentials(credentials: Credentials) = - credentials(JsonField.of(credentials)) - - /** - * Sets [Builder.credentials] to an arbitrary JSON value. - * - * You should usually call [Builder.credentials] with a well-typed [Credentials] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun credentials(credentials: JsonField) = apply { - this.credentials = credentials - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GoogleAuthOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): GoogleAuthOptions = - GoogleAuthOptions(credentials, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): GoogleAuthOptions = apply { - if (validated) { - return@apply - } - - credentials().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (credentials.asKnown().getOrNull()?.validity() ?: 0) - - class Credentials - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val authProviderX509CertUrl: JsonField, - private val authUri: JsonField, - private val clientEmail: JsonField, - private val clientId: JsonField, - private val clientX509CertUrl: JsonField, - private val privateKey: JsonField, - private val privateKeyId: JsonField, - private val projectId: JsonField, - private val tokenUri: JsonField, - private val type: JsonField, - private val universeDomain: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("auth_provider_x509_cert_url") - @ExcludeMissing - authProviderX509CertUrl: JsonField = JsonMissing.of(), - @JsonProperty("auth_uri") - @ExcludeMissing - authUri: JsonField = JsonMissing.of(), - @JsonProperty("client_email") - @ExcludeMissing - clientEmail: JsonField = JsonMissing.of(), - @JsonProperty("client_id") - @ExcludeMissing - clientId: JsonField = JsonMissing.of(), - @JsonProperty("client_x509_cert_url") - @ExcludeMissing - clientX509CertUrl: JsonField = JsonMissing.of(), - @JsonProperty("private_key") - @ExcludeMissing - privateKey: JsonField = JsonMissing.of(), - @JsonProperty("private_key_id") - @ExcludeMissing - privateKeyId: JsonField = JsonMissing.of(), - @JsonProperty("project_id") - @ExcludeMissing - projectId: JsonField = JsonMissing.of(), - @JsonProperty("token_uri") - @ExcludeMissing - tokenUri: JsonField = JsonMissing.of(), - @JsonProperty("type") - @ExcludeMissing - type: JsonField = JsonMissing.of(), - @JsonProperty("universe_domain") - @ExcludeMissing - universeDomain: JsonField = JsonMissing.of(), - ) : this( - authProviderX509CertUrl, - authUri, - clientEmail, - clientId, - clientX509CertUrl, - privateKey, - privateKeyId, - projectId, - tokenUri, - type, - universeDomain, - mutableMapOf(), - ) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun authProviderX509CertUrl(): Optional = - authProviderX509CertUrl.getOptional("auth_provider_x509_cert_url") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun authUri(): Optional = authUri.getOptional("auth_uri") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun clientEmail(): Optional = clientEmail.getOptional("client_email") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun clientId(): Optional = clientId.getOptional("client_id") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun clientX509CertUrl(): Optional = - clientX509CertUrl.getOptional("client_x509_cert_url") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun privateKey(): Optional = privateKey.getOptional("private_key") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun privateKeyId(): Optional = - privateKeyId.getOptional("private_key_id") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun projectId(): Optional = projectId.getOptional("project_id") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun tokenUri(): Optional = tokenUri.getOptional("token_uri") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun universeDomain(): Optional = - universeDomain.getOptional("universe_domain") - - /** - * Returns the raw JSON value of [authProviderX509CertUrl]. - * - * Unlike [authProviderX509CertUrl], this method doesn't throw if the JSON field - * has an unexpected type. - */ - @JsonProperty("auth_provider_x509_cert_url") - @ExcludeMissing - fun _authProviderX509CertUrl(): JsonField = authProviderX509CertUrl - - /** - * Returns the raw JSON value of [authUri]. - * - * Unlike [authUri], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("auth_uri") - @ExcludeMissing - fun _authUri(): JsonField = authUri - - /** - * Returns the raw JSON value of [clientEmail]. - * - * Unlike [clientEmail], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("client_email") - @ExcludeMissing - fun _clientEmail(): JsonField = clientEmail - - /** - * Returns the raw JSON value of [clientId]. - * - * Unlike [clientId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("client_id") - @ExcludeMissing - fun _clientId(): JsonField = clientId - - /** - * Returns the raw JSON value of [clientX509CertUrl]. - * - * Unlike [clientX509CertUrl], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("client_x509_cert_url") - @ExcludeMissing - fun _clientX509CertUrl(): JsonField = clientX509CertUrl - - /** - * Returns the raw JSON value of [privateKey]. - * - * Unlike [privateKey], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("private_key") - @ExcludeMissing - fun _privateKey(): JsonField = privateKey - - /** - * Returns the raw JSON value of [privateKeyId]. - * - * Unlike [privateKeyId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("private_key_id") - @ExcludeMissing - fun _privateKeyId(): JsonField = privateKeyId - - /** - * Returns the raw JSON value of [projectId]. - * - * Unlike [projectId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("project_id") - @ExcludeMissing - fun _projectId(): JsonField = projectId - - /** - * Returns the raw JSON value of [tokenUri]. - * - * Unlike [tokenUri], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("token_uri") - @ExcludeMissing - fun _tokenUri(): JsonField = tokenUri - - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - - /** - * Returns the raw JSON value of [universeDomain]. - * - * Unlike [universeDomain], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("universe_domain") - @ExcludeMissing - fun _universeDomain(): JsonField = universeDomain - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Credentials]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Credentials]. */ - class Builder internal constructor() { - - private var authProviderX509CertUrl: JsonField = JsonMissing.of() - private var authUri: JsonField = JsonMissing.of() - private var clientEmail: JsonField = JsonMissing.of() - private var clientId: JsonField = JsonMissing.of() - private var clientX509CertUrl: JsonField = JsonMissing.of() - private var privateKey: JsonField = JsonMissing.of() - private var privateKeyId: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var tokenUri: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var universeDomain: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(credentials: Credentials) = apply { - authProviderX509CertUrl = credentials.authProviderX509CertUrl - authUri = credentials.authUri - clientEmail = credentials.clientEmail - clientId = credentials.clientId - clientX509CertUrl = credentials.clientX509CertUrl - privateKey = credentials.privateKey - privateKeyId = credentials.privateKeyId - projectId = credentials.projectId - tokenUri = credentials.tokenUri - type = credentials.type - universeDomain = credentials.universeDomain - additionalProperties = credentials.additionalProperties.toMutableMap() - } - - fun authProviderX509CertUrl(authProviderX509CertUrl: String) = - authProviderX509CertUrl(JsonField.of(authProviderX509CertUrl)) - - /** - * Sets [Builder.authProviderX509CertUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.authProviderX509CertUrl] with a - * well-typed [String] value instead. This method is primarily for setting - * the field to an undocumented or not yet supported value. - */ - fun authProviderX509CertUrl(authProviderX509CertUrl: JsonField) = - apply { - this.authProviderX509CertUrl = authProviderX509CertUrl - } - - fun authUri(authUri: String) = authUri(JsonField.of(authUri)) - - /** - * Sets [Builder.authUri] to an arbitrary JSON value. - * - * You should usually call [Builder.authUri] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun authUri(authUri: JsonField) = apply { this.authUri = authUri } - - fun clientEmail(clientEmail: String) = - clientEmail(JsonField.of(clientEmail)) - - /** - * Sets [Builder.clientEmail] to an arbitrary JSON value. - * - * You should usually call [Builder.clientEmail] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun clientEmail(clientEmail: JsonField) = apply { - this.clientEmail = clientEmail - } - - fun clientId(clientId: String) = clientId(JsonField.of(clientId)) - - /** - * Sets [Builder.clientId] to an arbitrary JSON value. - * - * You should usually call [Builder.clientId] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun clientId(clientId: JsonField) = apply { - this.clientId = clientId - } - - fun clientX509CertUrl(clientX509CertUrl: String) = - clientX509CertUrl(JsonField.of(clientX509CertUrl)) - - /** - * Sets [Builder.clientX509CertUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.clientX509CertUrl] with a well-typed - * [String] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. - */ - fun clientX509CertUrl(clientX509CertUrl: JsonField) = apply { - this.clientX509CertUrl = clientX509CertUrl - } - - fun privateKey(privateKey: String) = privateKey(JsonField.of(privateKey)) - - /** - * Sets [Builder.privateKey] to an arbitrary JSON value. - * - * You should usually call [Builder.privateKey] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun privateKey(privateKey: JsonField) = apply { - this.privateKey = privateKey - } - - fun privateKeyId(privateKeyId: String) = - privateKeyId(JsonField.of(privateKeyId)) - - /** - * Sets [Builder.privateKeyId] to an arbitrary JSON value. - * - * You should usually call [Builder.privateKeyId] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun privateKeyId(privateKeyId: JsonField) = apply { - this.privateKeyId = privateKeyId - } - - fun projectId(projectId: String) = projectId(JsonField.of(projectId)) - - /** - * Sets [Builder.projectId] to an arbitrary JSON value. - * - * You should usually call [Builder.projectId] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun projectId(projectId: JsonField) = apply { - this.projectId = projectId - } - - fun tokenUri(tokenUri: String) = tokenUri(JsonField.of(tokenUri)) - - /** - * Sets [Builder.tokenUri] to an arbitrary JSON value. - * - * You should usually call [Builder.tokenUri] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun tokenUri(tokenUri: JsonField) = apply { - this.tokenUri = tokenUri - } - - fun type(type: String) = type(JsonField.of(type)) - - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [String] value - * instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } - - fun universeDomain(universeDomain: String) = - universeDomain(JsonField.of(universeDomain)) - - /** - * Sets [Builder.universeDomain] to an arbitrary JSON value. - * - * You should usually call [Builder.universeDomain] with a well-typed - * [String] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. - */ - fun universeDomain(universeDomain: JsonField) = apply { - this.universeDomain = universeDomain - } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Credentials]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Credentials = - Credentials( - authProviderX509CertUrl, - authUri, - clientEmail, - clientId, - clientX509CertUrl, - privateKey, - privateKeyId, - projectId, - tokenUri, - type, - universeDomain, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Credentials = apply { - if (validated) { - return@apply - } - - authProviderX509CertUrl() - authUri() - clientEmail() - clientId() - clientX509CertUrl() - privateKey() - privateKeyId() - projectId() - tokenUri() - type() - universeDomain() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (authProviderX509CertUrl.asKnown().isPresent) 1 else 0) + - (if (authUri.asKnown().isPresent) 1 else 0) + - (if (clientEmail.asKnown().isPresent) 1 else 0) + - (if (clientId.asKnown().isPresent) 1 else 0) + - (if (clientX509CertUrl.asKnown().isPresent) 1 else 0) + - (if (privateKey.asKnown().isPresent) 1 else 0) + - (if (privateKeyId.asKnown().isPresent) 1 else 0) + - (if (projectId.asKnown().isPresent) 1 else 0) + - (if (tokenUri.asKnown().isPresent) 1 else 0) + - (if (type.asKnown().isPresent) 1 else 0) + - (if (universeDomain.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Credentials && - authProviderX509CertUrl == other.authProviderX509CertUrl && - authUri == other.authUri && - clientEmail == other.clientEmail && - clientId == other.clientId && - clientX509CertUrl == other.clientX509CertUrl && - privateKey == other.privateKey && - privateKeyId == other.privateKeyId && - projectId == other.projectId && - tokenUri == other.tokenUri && - type == other.type && - universeDomain == other.universeDomain && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - authProviderX509CertUrl, - authUri, - clientEmail, - clientId, - clientX509CertUrl, - privateKey, - privateKeyId, - projectId, - tokenUri, - type, - universeDomain, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Credentials{authProviderX509CertUrl=$authProviderX509CertUrl, authUri=$authUri, clientEmail=$clientEmail, clientId=$clientId, clientX509CertUrl=$clientX509CertUrl, privateKey=$privateKey, privateKeyId=$privateKeyId, projectId=$projectId, tokenUri=$tokenUri, type=$type, universeDomain=$universeDomain, additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GoogleAuthOptions && - credentials == other.credentials && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(credentials, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GoogleAuthOptions{credentials=$credentials, additionalProperties=$additionalProperties}" - } - - /** Custom headers for Vertex AI requests */ - class Headers - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Headers]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Headers]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(headers: Headers) = apply { - additionalProperties = headers.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Headers]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Headers = Headers(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Headers = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Headers && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Headers{additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GoogleVertexProviderOptions && - googleAuthOptions == other.googleAuthOptions && - headers == other.headers && - location == other.location && - project == other.project && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(googleAuthOptions, headers, location, project, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GoogleVertexProviderOptions{googleAuthOptions=$googleAuthOptions, headers=$headers, location=$location, project=$project, additionalProperties=$additionalProperties}" - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -2513,26 +551,15 @@ private constructor( baseUrl == other.baseUrl && headers == other.headers && provider == other.provider && - providerOptions == other.providerOptions && - skipApiKeyFallback == other.skipApiKeyFallback && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash( - modelName, - apiKey, - baseUrl, - headers, - provider, - providerOptions, - skipApiKeyFallback, - additionalProperties, - ) + Objects.hash(modelName, apiKey, baseUrl, headers, provider, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, provider=$provider, providerOptions=$providerOptions, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" + "ModelConfig{modelName=$modelName, apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, provider=$provider, additionalProperties=$additionalProperties}" } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index 65fd5a6..f68232a 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -1686,6 +1686,8 @@ private constructor( private val instruction: JsonField, private val highlightCursor: JsonField, private val maxSteps: JsonField, + private val toolTimeout: JsonField, + private val useSearch: JsonField, private val additionalProperties: MutableMap, ) { @@ -1697,8 +1699,16 @@ private constructor( @JsonProperty("highlightCursor") @ExcludeMissing highlightCursor: JsonField = JsonMissing.of(), - @JsonProperty("maxSteps") @ExcludeMissing maxSteps: JsonField = JsonMissing.of(), - ) : this(instruction, highlightCursor, maxSteps, mutableMapOf()) + @JsonProperty("maxSteps") + @ExcludeMissing + maxSteps: JsonField = JsonMissing.of(), + @JsonProperty("toolTimeout") + @ExcludeMissing + toolTimeout: JsonField = JsonMissing.of(), + @JsonProperty("useSearch") + @ExcludeMissing + useSearch: JsonField = JsonMissing.of(), + ) : this(instruction, highlightCursor, maxSteps, toolTimeout, useSearch, mutableMapOf()) /** * Natural language instruction for the agent @@ -1724,6 +1734,22 @@ private constructor( */ fun maxSteps(): Optional = maxSteps.getOptional("maxSteps") + /** + * Timeout in milliseconds for each agent tool call + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun toolTimeout(): Optional = toolTimeout.getOptional("toolTimeout") + + /** + * Whether to enable the web search tool powered by Browserbase Search API + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun useSearch(): Optional = useSearch.getOptional("useSearch") + /** * Returns the raw JSON value of [instruction]. * @@ -1750,6 +1776,22 @@ private constructor( */ @JsonProperty("maxSteps") @ExcludeMissing fun _maxSteps(): JsonField = maxSteps + /** + * Returns the raw JSON value of [toolTimeout]. + * + * Unlike [toolTimeout], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("toolTimeout") + @ExcludeMissing + fun _toolTimeout(): JsonField = toolTimeout + + /** + * Returns the raw JSON value of [useSearch]. + * + * Unlike [useSearch], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("useSearch") @ExcludeMissing fun _useSearch(): JsonField = useSearch + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1781,6 +1823,8 @@ private constructor( private var instruction: JsonField? = null private var highlightCursor: JsonField = JsonMissing.of() private var maxSteps: JsonField = JsonMissing.of() + private var toolTimeout: JsonField = JsonMissing.of() + private var useSearch: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -1788,6 +1832,8 @@ private constructor( instruction = executeOptions.instruction highlightCursor = executeOptions.highlightCursor maxSteps = executeOptions.maxSteps + toolTimeout = executeOptions.toolTimeout + useSearch = executeOptions.useSearch additionalProperties = executeOptions.additionalProperties.toMutableMap() } @@ -1832,6 +1878,32 @@ private constructor( */ fun maxSteps(maxSteps: JsonField) = apply { this.maxSteps = maxSteps } + /** Timeout in milliseconds for each agent tool call */ + fun toolTimeout(toolTimeout: Double) = toolTimeout(JsonField.of(toolTimeout)) + + /** + * Sets [Builder.toolTimeout] to an arbitrary JSON value. + * + * You should usually call [Builder.toolTimeout] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun toolTimeout(toolTimeout: JsonField) = apply { + this.toolTimeout = toolTimeout + } + + /** Whether to enable the web search tool powered by Browserbase Search API */ + fun useSearch(useSearch: Boolean) = useSearch(JsonField.of(useSearch)) + + /** + * Sets [Builder.useSearch] to an arbitrary JSON value. + * + * You should usually call [Builder.useSearch] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun useSearch(useSearch: JsonField) = apply { this.useSearch = useSearch } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1868,6 +1940,8 @@ private constructor( checkRequired("instruction", instruction), highlightCursor, maxSteps, + toolTimeout, + useSearch, additionalProperties.toMutableMap(), ) } @@ -1882,6 +1956,8 @@ private constructor( instruction() highlightCursor() maxSteps() + toolTimeout() + useSearch() validated = true } @@ -1903,7 +1979,9 @@ private constructor( internal fun validity(): Int = (if (instruction.asKnown().isPresent) 1 else 0) + (if (highlightCursor.asKnown().isPresent) 1 else 0) + - (if (maxSteps.asKnown().isPresent) 1 else 0) + (if (maxSteps.asKnown().isPresent) 1 else 0) + + (if (toolTimeout.asKnown().isPresent) 1 else 0) + + (if (useSearch.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -1914,17 +1992,26 @@ private constructor( instruction == other.instruction && highlightCursor == other.highlightCursor && maxSteps == other.maxSteps && + toolTimeout == other.toolTimeout && + useSearch == other.useSearch && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(instruction, highlightCursor, maxSteps, additionalProperties) + Objects.hash( + instruction, + highlightCursor, + maxSteps, + toolTimeout, + useSearch, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, additionalProperties=$additionalProperties}" + "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, toolTimeout=$toolTimeout, useSearch=$useSearch, additionalProperties=$additionalProperties}" } /** Whether to stream the response via SSE */ diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index a2fba41..994401f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -100,15 +100,6 @@ private constructor( */ fun experimental(): Optional = body.experimental() - /** - * Optional provider-specific configuration for the session model (for example Bedrock region - * and credentials) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun modelClientOptions(): Optional = body.modelClientOptions() - /** * Enable self-healing for failed actions * @@ -194,14 +185,6 @@ private constructor( */ fun _experimental(): JsonField = body._experimental() - /** - * Returns the raw JSON value of [modelClientOptions]. - * - * Unlike [modelClientOptions], this method doesn't throw if the JSON field has an unexpected - * type. - */ - fun _modelClientOptions(): JsonField = body._modelClientOptions() - /** * Returns the raw JSON value of [selfHeal]. * @@ -389,47 +372,6 @@ private constructor( body.experimental(experimental) } - /** - * Optional provider-specific configuration for the session model (for example Bedrock - * region and credentials) - */ - fun modelClientOptions(modelClientOptions: ModelClientOptions) = apply { - body.modelClientOptions(modelClientOptions) - } - - /** - * Sets [Builder.modelClientOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.modelClientOptions] with a well-typed - * [ModelClientOptions] value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun modelClientOptions(modelClientOptions: JsonField) = apply { - body.modelClientOptions(modelClientOptions) - } - - /** - * Alias for calling [modelClientOptions] with - * `ModelClientOptions.ofBedrockApiKey(bedrockApiKey)`. - */ - fun modelClientOptions(bedrockApiKey: ModelClientOptions.BedrockApiKeyModelClientOptions) = - apply { - body.modelClientOptions(bedrockApiKey) - } - - /** - * Alias for calling [modelClientOptions] with - * `ModelClientOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. - */ - fun modelClientOptions( - bedrockAwsCredentials: ModelClientOptions.BedrockAwsCredentialsModelClientOptions - ) = apply { body.modelClientOptions(bedrockAwsCredentials) } - - /** Alias for calling [modelClientOptions] with `ModelClientOptions.ofGeneric(generic)`. */ - fun modelClientOptions(generic: ModelClientOptions.GenericModelClientOptions) = apply { - body.modelClientOptions(generic) - } - /** Enable self-healing for failed actions */ fun selfHeal(selfHeal: Boolean) = apply { body.selfHeal(selfHeal) } @@ -643,7 +585,6 @@ private constructor( private val browserbaseSessionId: JsonField, private val domSettleTimeoutMs: JsonField, private val experimental: JsonField, - private val modelClientOptions: JsonField, private val selfHeal: JsonField, private val systemPrompt: JsonField, private val verbose: JsonField, @@ -673,9 +614,6 @@ private constructor( @JsonProperty("experimental") @ExcludeMissing experimental: JsonField = JsonMissing.of(), - @JsonProperty("modelClientOptions") - @ExcludeMissing - modelClientOptions: JsonField = JsonMissing.of(), @JsonProperty("selfHeal") @ExcludeMissing selfHeal: JsonField = JsonMissing.of(), @@ -694,7 +632,6 @@ private constructor( browserbaseSessionId, domSettleTimeoutMs, experimental, - modelClientOptions, selfHeal, systemPrompt, verbose, @@ -755,16 +692,6 @@ private constructor( */ fun experimental(): Optional = experimental.getOptional("experimental") - /** - * Optional provider-specific configuration for the session model (for example Bedrock - * region and credentials) - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun modelClientOptions(): Optional = - modelClientOptions.getOptional("modelClientOptions") - /** * Enable self-healing for failed actions * @@ -863,16 +790,6 @@ private constructor( @ExcludeMissing fun _experimental(): JsonField = experimental - /** - * Returns the raw JSON value of [modelClientOptions]. - * - * Unlike [modelClientOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("modelClientOptions") - @ExcludeMissing - fun _modelClientOptions(): JsonField = modelClientOptions - /** * Returns the raw JSON value of [selfHeal]. * @@ -943,7 +860,6 @@ private constructor( private var browserbaseSessionId: JsonField = JsonMissing.of() private var domSettleTimeoutMs: JsonField = JsonMissing.of() private var experimental: JsonField = JsonMissing.of() - private var modelClientOptions: JsonField = JsonMissing.of() private var selfHeal: JsonField = JsonMissing.of() private var systemPrompt: JsonField = JsonMissing.of() private var verbose: JsonField = JsonMissing.of() @@ -959,7 +875,6 @@ private constructor( browserbaseSessionId = body.browserbaseSessionId domSettleTimeoutMs = body.domSettleTimeoutMs experimental = body.experimental - modelClientOptions = body.modelClientOptions selfHeal = body.selfHeal systemPrompt = body.systemPrompt verbose = body.verbose @@ -1062,49 +977,6 @@ private constructor( this.experimental = experimental } - /** - * Optional provider-specific configuration for the session model (for example Bedrock - * region and credentials) - */ - fun modelClientOptions(modelClientOptions: ModelClientOptions) = - modelClientOptions(JsonField.of(modelClientOptions)) - - /** - * Sets [Builder.modelClientOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.modelClientOptions] with a well-typed - * [ModelClientOptions] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. - */ - fun modelClientOptions(modelClientOptions: JsonField) = apply { - this.modelClientOptions = modelClientOptions - } - - /** - * Alias for calling [modelClientOptions] with - * `ModelClientOptions.ofBedrockApiKey(bedrockApiKey)`. - */ - fun modelClientOptions( - bedrockApiKey: ModelClientOptions.BedrockApiKeyModelClientOptions - ) = modelClientOptions(ModelClientOptions.ofBedrockApiKey(bedrockApiKey)) - - /** - * Alias for calling [modelClientOptions] with - * `ModelClientOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. - */ - fun modelClientOptions( - bedrockAwsCredentials: ModelClientOptions.BedrockAwsCredentialsModelClientOptions - ) = - modelClientOptions( - ModelClientOptions.ofBedrockAwsCredentials(bedrockAwsCredentials) - ) - - /** - * Alias for calling [modelClientOptions] with `ModelClientOptions.ofGeneric(generic)`. - */ - fun modelClientOptions(generic: ModelClientOptions.GenericModelClientOptions) = - modelClientOptions(ModelClientOptions.ofGeneric(generic)) - /** Enable self-healing for failed actions */ fun selfHeal(selfHeal: Boolean) = selfHeal(JsonField.of(selfHeal)) @@ -1198,7 +1070,6 @@ private constructor( browserbaseSessionId, domSettleTimeoutMs, experimental, - modelClientOptions, selfHeal, systemPrompt, verbose, @@ -1221,7 +1092,6 @@ private constructor( browserbaseSessionId() domSettleTimeoutMs() experimental() - modelClientOptions().ifPresent { it.validate() } selfHeal() systemPrompt() verbose().ifPresent { it.validate() } @@ -1252,7 +1122,6 @@ private constructor( (if (browserbaseSessionId.asKnown().isPresent) 1 else 0) + (if (domSettleTimeoutMs.asKnown().isPresent) 1 else 0) + (if (experimental.asKnown().isPresent) 1 else 0) + - (modelClientOptions.asKnown().getOrNull()?.validity() ?: 0) + (if (selfHeal.asKnown().isPresent) 1 else 0) + (if (systemPrompt.asKnown().isPresent) 1 else 0) + (verbose.asKnown().getOrNull()?.validity() ?: 0) + @@ -1271,7 +1140,6 @@ private constructor( browserbaseSessionId == other.browserbaseSessionId && domSettleTimeoutMs == other.domSettleTimeoutMs && experimental == other.experimental && - modelClientOptions == other.modelClientOptions && selfHeal == other.selfHeal && systemPrompt == other.systemPrompt && verbose == other.verbose && @@ -1288,7 +1156,6 @@ private constructor( browserbaseSessionId, domSettleTimeoutMs, experimental, - modelClientOptions, selfHeal, systemPrompt, verbose, @@ -1300,7 +1167,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, modelClientOptions=$modelClientOptions, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" + "Body{modelName=$modelName, actTimeoutMs=$actTimeoutMs, browser=$browser, browserbaseSessionCreateParams=$browserbaseSessionCreateParams, browserbaseSessionId=$browserbaseSessionId, domSettleTimeoutMs=$domSettleTimeoutMs, experimental=$experimental, selfHeal=$selfHeal, systemPrompt=$systemPrompt, verbose=$verbose, waitForCaptchaSolves=$waitForCaptchaSolves, additionalProperties=$additionalProperties}" } class Browser @@ -7632,3960 +7499,6 @@ private constructor( "BrowserbaseSessionCreateParams{browserSettings=$browserSettings, extensionId=$extensionId, keepAlive=$keepAlive, projectId=$projectId, proxies=$proxies, region=$region, timeout=$timeout, userMetadata=$userMetadata, additionalProperties=$additionalProperties}" } - /** - * Optional provider-specific configuration for the session model (for example Bedrock region - * and credentials) - */ - @JsonDeserialize(using = ModelClientOptions.Deserializer::class) - @JsonSerialize(using = ModelClientOptions.Serializer::class) - class ModelClientOptions - private constructor( - private val bedrockApiKey: BedrockApiKeyModelClientOptions? = null, - private val bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions? = null, - private val generic: GenericModelClientOptions? = null, - private val _json: JsonValue? = null, - ) { - - fun bedrockApiKey(): Optional = - Optional.ofNullable(bedrockApiKey) - - fun bedrockAwsCredentials(): Optional = - Optional.ofNullable(bedrockAwsCredentials) - - fun generic(): Optional = Optional.ofNullable(generic) - - fun isBedrockApiKey(): Boolean = bedrockApiKey != null - - fun isBedrockAwsCredentials(): Boolean = bedrockAwsCredentials != null - - fun isGeneric(): Boolean = generic != null - - fun asBedrockApiKey(): BedrockApiKeyModelClientOptions = - bedrockApiKey.getOrThrow("bedrockApiKey") - - fun asBedrockAwsCredentials(): BedrockAwsCredentialsModelClientOptions = - bedrockAwsCredentials.getOrThrow("bedrockAwsCredentials") - - fun asGeneric(): GenericModelClientOptions = generic.getOrThrow("generic") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - bedrockApiKey != null -> visitor.visitBedrockApiKey(bedrockApiKey) - bedrockAwsCredentials != null -> - visitor.visitBedrockAwsCredentials(bedrockAwsCredentials) - generic != null -> visitor.visitGeneric(generic) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): ModelClientOptions = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitBedrockApiKey( - bedrockApiKey: BedrockApiKeyModelClientOptions - ) { - bedrockApiKey.validate() - } - - override fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions - ) { - bedrockAwsCredentials.validate() - } - - override fun visitGeneric(generic: GenericModelClientOptions) { - generic.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitBedrockApiKey( - bedrockApiKey: BedrockApiKeyModelClientOptions - ) = bedrockApiKey.validity() - - override fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions - ) = bedrockAwsCredentials.validity() - - override fun visitGeneric(generic: GenericModelClientOptions) = - generic.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ModelClientOptions && - bedrockApiKey == other.bedrockApiKey && - bedrockAwsCredentials == other.bedrockAwsCredentials && - generic == other.generic - } - - override fun hashCode(): Int = Objects.hash(bedrockApiKey, bedrockAwsCredentials, generic) - - override fun toString(): String = - when { - bedrockApiKey != null -> "ModelClientOptions{bedrockApiKey=$bedrockApiKey}" - bedrockAwsCredentials != null -> - "ModelClientOptions{bedrockAwsCredentials=$bedrockAwsCredentials}" - generic != null -> "ModelClientOptions{generic=$generic}" - _json != null -> "ModelClientOptions{_unknown=$_json}" - else -> throw IllegalStateException("Invalid ModelClientOptions") - } - - companion object { - - @JvmStatic - fun ofBedrockApiKey(bedrockApiKey: BedrockApiKeyModelClientOptions) = - ModelClientOptions(bedrockApiKey = bedrockApiKey) - - @JvmStatic - fun ofBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions - ) = ModelClientOptions(bedrockAwsCredentials = bedrockAwsCredentials) - - @JvmStatic - fun ofGeneric(generic: GenericModelClientOptions) = - ModelClientOptions(generic = generic) - } - - /** - * An interface that defines how to map each variant of [ModelClientOptions] to a value of - * type [T]. - */ - interface Visitor { - - fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyModelClientOptions): T - - fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsModelClientOptions - ): T - - fun visitGeneric(generic: GenericModelClientOptions): T - - /** - * Maps an unknown variant of [ModelClientOptions] to a value of type [T]. - * - * An instance of [ModelClientOptions] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, if the SDK - * is on an older version than the API, then the API may respond with new variants that - * the SDK is unaware of. - * - * @throws StagehandInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown ModelClientOptions: $json") - } - } - - internal class Deserializer : - BaseDeserializer(ModelClientOptions::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): ModelClientOptions { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { ModelClientOptions(bedrockApiKey = it, _json = json) }, - tryDeserialize( - node, - jacksonTypeRef(), - ) - ?.let { - ModelClientOptions(bedrockAwsCredentials = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - ModelClientOptions(generic = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible with - // all the possible variants (e.g. deserializing from boolean). - 0 -> ModelClientOptions(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the first - // completely valid match, or simply the first match if none are completely - // valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(ModelClientOptions::class) { - - override fun serialize( - value: ModelClientOptions, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.bedrockApiKey != null -> generator.writeObject(value.bedrockApiKey) - value.bedrockAwsCredentials != null -> - generator.writeObject(value.bedrockAwsCredentials) - value.generic != null -> generator.writeObject(value.generic) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid ModelClientOptions") - } - } - } - - class BedrockApiKeyModelClientOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val apiKey: JsonField, - private val providerOptions: JsonField, - private val baseUrl: JsonField, - private val headers: JsonField, - private val skipApiKeyFallback: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("apiKey") - @ExcludeMissing - apiKey: JsonField = JsonMissing.of(), - @JsonProperty("providerOptions") - @ExcludeMissing - providerOptions: JsonField = JsonMissing.of(), - @JsonProperty("baseURL") - @ExcludeMissing - baseUrl: JsonField = JsonMissing.of(), - @JsonProperty("headers") - @ExcludeMissing - headers: JsonField = JsonMissing.of(), - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - skipApiKeyFallback: JsonField = JsonMissing.of(), - ) : this(apiKey, providerOptions, baseUrl, headers, skipApiKeyFallback, mutableMapOf()) - - /** - * Short-term Bedrock API key for bearer-token auth - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun apiKey(): String = apiKey.getRequired("apiKey") - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun providerOptions(): ProviderOptions = providerOptions.getRequired("providerOptions") - - /** - * Base URL for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun baseUrl(): Optional = baseUrl.getOptional("baseURL") - - /** - * Custom headers for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun headers(): Optional = headers.getOptional("headers") - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this - * when auth is carried through providerOptions instead of an API key. - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun skipApiKeyFallback(): Optional = - skipApiKeyFallback.getOptional("skipApiKeyFallback") - - /** - * Returns the raw JSON value of [apiKey]. - * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey - - /** - * Returns the raw JSON value of [providerOptions]. - * - * Unlike [providerOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("providerOptions") - @ExcludeMissing - fun _providerOptions(): JsonField = providerOptions - - /** - * Returns the raw JSON value of [baseUrl]. - * - * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl - - /** - * Returns the raw JSON value of [headers]. - * - * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers - - /** - * Returns the raw JSON value of [skipApiKeyFallback]. - * - * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [BedrockApiKeyModelClientOptions]. - * - * The following fields are required: - * ```java - * .apiKey() - * .providerOptions() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [BedrockApiKeyModelClientOptions]. */ - class Builder internal constructor() { - - private var apiKey: JsonField? = null - private var providerOptions: JsonField? = null - private var baseUrl: JsonField = JsonMissing.of() - private var headers: JsonField = JsonMissing.of() - private var skipApiKeyFallback: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from( - bedrockApiKeyModelClientOptions: BedrockApiKeyModelClientOptions - ) = apply { - apiKey = bedrockApiKeyModelClientOptions.apiKey - providerOptions = bedrockApiKeyModelClientOptions.providerOptions - baseUrl = bedrockApiKeyModelClientOptions.baseUrl - headers = bedrockApiKeyModelClientOptions.headers - skipApiKeyFallback = bedrockApiKeyModelClientOptions.skipApiKeyFallback - additionalProperties = - bedrockApiKeyModelClientOptions.additionalProperties.toMutableMap() - } - - /** Short-term Bedrock API key for bearer-token auth */ - fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) - - /** - * Sets [Builder.apiKey] to an arbitrary JSON value. - * - * You should usually call [Builder.apiKey] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } - - fun providerOptions(providerOptions: ProviderOptions) = - providerOptions(JsonField.of(providerOptions)) - - /** - * Sets [Builder.providerOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.providerOptions] with a well-typed - * [ProviderOptions] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun providerOptions(providerOptions: JsonField) = apply { - this.providerOptions = providerOptions - } - - /** Base URL for the model provider */ - fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) - - /** - * Sets [Builder.baseUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.baseUrl] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - - /** Custom headers for the model provider */ - fun headers(headers: Headers) = headers(JsonField.of(headers)) - - /** - * Sets [Builder.headers] to an arbitrary JSON value. - * - * You should usually call [Builder.headers] with a well-typed [Headers] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun headers(headers: JsonField) = apply { this.headers = headers } - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use - * this when auth is carried through providerOptions instead of an API key. - */ - fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = - skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) - - /** - * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. - * - * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. - */ - fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { - this.skipApiKeyFallback = skipApiKeyFallback - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [BedrockApiKeyModelClientOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .apiKey() - * .providerOptions() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): BedrockApiKeyModelClientOptions = - BedrockApiKeyModelClientOptions( - checkRequired("apiKey", apiKey), - checkRequired("providerOptions", providerOptions), - baseUrl, - headers, - skipApiKeyFallback, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): BedrockApiKeyModelClientOptions = apply { - if (validated) { - return@apply - } - - apiKey() - providerOptions().validate() - baseUrl() - headers().ifPresent { it.validate() } - skipApiKeyFallback() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (apiKey.asKnown().isPresent) 1 else 0) + - (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + - (if (baseUrl.asKnown().isPresent) 1 else 0) + - (headers.asKnown().getOrNull()?.validity() ?: 0) + - (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) - - class ProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val region: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("region") - @ExcludeMissing - region: JsonField = JsonMissing.of() - ) : this(region, mutableMapOf()) - - /** - * AWS region for Amazon Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or - * is unexpectedly missing or null (e.g. if the server responded with an - * unexpected value). - */ - fun region(): String = region.getRequired("region") - - /** - * Returns the raw JSON value of [region]. - * - * Unlike [region], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ProviderOptions]. - * - * The following fields are required: - * ```java - * .region() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ProviderOptions]. */ - class Builder internal constructor() { - - private var region: JsonField? = null - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(providerOptions: ProviderOptions) = apply { - region = providerOptions.region - additionalProperties = providerOptions.additionalProperties.toMutableMap() - } - - /** AWS region for Amazon Bedrock */ - fun region(region: String) = region(JsonField.of(region)) - - /** - * Sets [Builder.region] to an arbitrary JSON value. - * - * You should usually call [Builder.region] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun region(region: JsonField) = apply { this.region = region } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [ProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .region() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ProviderOptions = - ProviderOptions( - checkRequired("region", region), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): ProviderOptions = apply { - if (validated) { - return@apply - } - - region() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (if (region.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProviderOptions && - region == other.region && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(region, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "ProviderOptions{region=$region, additionalProperties=$additionalProperties}" - } - - /** Custom headers for the model provider */ - class Headers - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Headers]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Headers]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(headers: Headers) = apply { - additionalProperties = headers.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Headers]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Headers = Headers(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Headers = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Headers && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Headers{additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BedrockApiKeyModelClientOptions && - apiKey == other.apiKey && - providerOptions == other.providerOptions && - baseUrl == other.baseUrl && - headers == other.headers && - skipApiKeyFallback == other.skipApiKeyFallback && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - apiKey, - providerOptions, - baseUrl, - headers, - skipApiKeyFallback, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "BedrockApiKeyModelClientOptions{apiKey=$apiKey, providerOptions=$providerOptions, baseUrl=$baseUrl, headers=$headers, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" - } - - class BedrockAwsCredentialsModelClientOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val providerOptions: JsonField, - private val baseUrl: JsonField, - private val headers: JsonField, - private val skipApiKeyFallback: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("providerOptions") - @ExcludeMissing - providerOptions: JsonField = JsonMissing.of(), - @JsonProperty("baseURL") - @ExcludeMissing - baseUrl: JsonField = JsonMissing.of(), - @JsonProperty("headers") - @ExcludeMissing - headers: JsonField = JsonMissing.of(), - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - skipApiKeyFallback: JsonField = JsonMissing.of(), - ) : this(providerOptions, baseUrl, headers, skipApiKeyFallback, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun providerOptions(): ProviderOptions = providerOptions.getRequired("providerOptions") - - /** - * Base URL for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun baseUrl(): Optional = baseUrl.getOptional("baseURL") - - /** - * Custom headers for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun headers(): Optional = headers.getOptional("headers") - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this - * when auth is carried through providerOptions instead of an API key. - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun skipApiKeyFallback(): Optional = - skipApiKeyFallback.getOptional("skipApiKeyFallback") - - /** - * Returns the raw JSON value of [providerOptions]. - * - * Unlike [providerOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("providerOptions") - @ExcludeMissing - fun _providerOptions(): JsonField = providerOptions - - /** - * Returns the raw JSON value of [baseUrl]. - * - * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl - - /** - * Returns the raw JSON value of [headers]. - * - * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers - - /** - * Returns the raw JSON value of [skipApiKeyFallback]. - * - * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [BedrockAwsCredentialsModelClientOptions]. - * - * The following fields are required: - * ```java - * .providerOptions() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [BedrockAwsCredentialsModelClientOptions]. */ - class Builder internal constructor() { - - private var providerOptions: JsonField? = null - private var baseUrl: JsonField = JsonMissing.of() - private var headers: JsonField = JsonMissing.of() - private var skipApiKeyFallback: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from( - bedrockAwsCredentialsModelClientOptions: BedrockAwsCredentialsModelClientOptions - ) = apply { - providerOptions = bedrockAwsCredentialsModelClientOptions.providerOptions - baseUrl = bedrockAwsCredentialsModelClientOptions.baseUrl - headers = bedrockAwsCredentialsModelClientOptions.headers - skipApiKeyFallback = bedrockAwsCredentialsModelClientOptions.skipApiKeyFallback - additionalProperties = - bedrockAwsCredentialsModelClientOptions.additionalProperties.toMutableMap() - } - - fun providerOptions(providerOptions: ProviderOptions) = - providerOptions(JsonField.of(providerOptions)) - - /** - * Sets [Builder.providerOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.providerOptions] with a well-typed - * [ProviderOptions] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun providerOptions(providerOptions: JsonField) = apply { - this.providerOptions = providerOptions - } - - /** Base URL for the model provider */ - fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) - - /** - * Sets [Builder.baseUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.baseUrl] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - - /** Custom headers for the model provider */ - fun headers(headers: Headers) = headers(JsonField.of(headers)) - - /** - * Sets [Builder.headers] to an arbitrary JSON value. - * - * You should usually call [Builder.headers] with a well-typed [Headers] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun headers(headers: JsonField) = apply { this.headers = headers } - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use - * this when auth is carried through providerOptions instead of an API key. - */ - fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = - skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) - - /** - * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. - * - * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. - */ - fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { - this.skipApiKeyFallback = skipApiKeyFallback - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [BedrockAwsCredentialsModelClientOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .providerOptions() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): BedrockAwsCredentialsModelClientOptions = - BedrockAwsCredentialsModelClientOptions( - checkRequired("providerOptions", providerOptions), - baseUrl, - headers, - skipApiKeyFallback, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): BedrockAwsCredentialsModelClientOptions = apply { - if (validated) { - return@apply - } - - providerOptions().validate() - baseUrl() - headers().ifPresent { it.validate() } - skipApiKeyFallback() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + - (if (baseUrl.asKnown().isPresent) 1 else 0) + - (headers.asKnown().getOrNull()?.validity() ?: 0) + - (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) - - class ProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val accessKeyId: JsonField, - private val region: JsonField, - private val secretAccessKey: JsonField, - private val sessionToken: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("accessKeyId") - @ExcludeMissing - accessKeyId: JsonField = JsonMissing.of(), - @JsonProperty("region") - @ExcludeMissing - region: JsonField = JsonMissing.of(), - @JsonProperty("secretAccessKey") - @ExcludeMissing - secretAccessKey: JsonField = JsonMissing.of(), - @JsonProperty("sessionToken") - @ExcludeMissing - sessionToken: JsonField = JsonMissing.of(), - ) : this(accessKeyId, region, secretAccessKey, sessionToken, mutableMapOf()) - - /** - * AWS access key ID for Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or - * is unexpectedly missing or null (e.g. if the server responded with an - * unexpected value). - */ - fun accessKeyId(): String = accessKeyId.getRequired("accessKeyId") - - /** - * AWS region for Amazon Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or - * is unexpectedly missing or null (e.g. if the server responded with an - * unexpected value). - */ - fun region(): String = region.getRequired("region") - - /** - * AWS secret access key for Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type or - * is unexpectedly missing or null (e.g. if the server responded with an - * unexpected value). - */ - fun secretAccessKey(): String = secretAccessKey.getRequired("secretAccessKey") - - /** - * Optional AWS session token for temporary credentials - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun sessionToken(): Optional = sessionToken.getOptional("sessionToken") - - /** - * Returns the raw JSON value of [accessKeyId]. - * - * Unlike [accessKeyId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("accessKeyId") - @ExcludeMissing - fun _accessKeyId(): JsonField = accessKeyId - - /** - * Returns the raw JSON value of [region]. - * - * Unlike [region], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("region") @ExcludeMissing fun _region(): JsonField = region - - /** - * Returns the raw JSON value of [secretAccessKey]. - * - * Unlike [secretAccessKey], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("secretAccessKey") - @ExcludeMissing - fun _secretAccessKey(): JsonField = secretAccessKey - - /** - * Returns the raw JSON value of [sessionToken]. - * - * Unlike [sessionToken], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("sessionToken") - @ExcludeMissing - fun _sessionToken(): JsonField = sessionToken - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [ProviderOptions]. - * - * The following fields are required: - * ```java - * .accessKeyId() - * .region() - * .secretAccessKey() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [ProviderOptions]. */ - class Builder internal constructor() { - - private var accessKeyId: JsonField? = null - private var region: JsonField? = null - private var secretAccessKey: JsonField? = null - private var sessionToken: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(providerOptions: ProviderOptions) = apply { - accessKeyId = providerOptions.accessKeyId - region = providerOptions.region - secretAccessKey = providerOptions.secretAccessKey - sessionToken = providerOptions.sessionToken - additionalProperties = providerOptions.additionalProperties.toMutableMap() - } - - /** AWS access key ID for Bedrock */ - fun accessKeyId(accessKeyId: String) = accessKeyId(JsonField.of(accessKeyId)) - - /** - * Sets [Builder.accessKeyId] to an arbitrary JSON value. - * - * You should usually call [Builder.accessKeyId] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun accessKeyId(accessKeyId: JsonField) = apply { - this.accessKeyId = accessKeyId - } - - /** AWS region for Amazon Bedrock */ - fun region(region: String) = region(JsonField.of(region)) - - /** - * Sets [Builder.region] to an arbitrary JSON value. - * - * You should usually call [Builder.region] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun region(region: JsonField) = apply { this.region = region } - - /** AWS secret access key for Bedrock */ - fun secretAccessKey(secretAccessKey: String) = - secretAccessKey(JsonField.of(secretAccessKey)) - - /** - * Sets [Builder.secretAccessKey] to an arbitrary JSON value. - * - * You should usually call [Builder.secretAccessKey] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun secretAccessKey(secretAccessKey: JsonField) = apply { - this.secretAccessKey = secretAccessKey - } - - /** Optional AWS session token for temporary credentials */ - fun sessionToken(sessionToken: String) = - sessionToken(JsonField.of(sessionToken)) - - /** - * Sets [Builder.sessionToken] to an arbitrary JSON value. - * - * You should usually call [Builder.sessionToken] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun sessionToken(sessionToken: JsonField) = apply { - this.sessionToken = sessionToken - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [ProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .accessKeyId() - * .region() - * .secretAccessKey() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): ProviderOptions = - ProviderOptions( - checkRequired("accessKeyId", accessKeyId), - checkRequired("region", region), - checkRequired("secretAccessKey", secretAccessKey), - sessionToken, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): ProviderOptions = apply { - if (validated) { - return@apply - } - - accessKeyId() - region() - secretAccessKey() - sessionToken() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (accessKeyId.asKnown().isPresent) 1 else 0) + - (if (region.asKnown().isPresent) 1 else 0) + - (if (secretAccessKey.asKnown().isPresent) 1 else 0) + - (if (sessionToken.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProviderOptions && - accessKeyId == other.accessKeyId && - region == other.region && - secretAccessKey == other.secretAccessKey && - sessionToken == other.sessionToken && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - accessKeyId, - region, - secretAccessKey, - sessionToken, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "ProviderOptions{accessKeyId=$accessKeyId, region=$region, secretAccessKey=$secretAccessKey, sessionToken=$sessionToken, additionalProperties=$additionalProperties}" - } - - /** Custom headers for the model provider */ - class Headers - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Headers]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Headers]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(headers: Headers) = apply { - additionalProperties = headers.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Headers]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Headers = Headers(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Headers = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Headers && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Headers{additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BedrockAwsCredentialsModelClientOptions && - providerOptions == other.providerOptions && - baseUrl == other.baseUrl && - headers == other.headers && - skipApiKeyFallback == other.skipApiKeyFallback && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - providerOptions, - baseUrl, - headers, - skipApiKeyFallback, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "BedrockAwsCredentialsModelClientOptions{providerOptions=$providerOptions, baseUrl=$baseUrl, headers=$headers, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" - } - - class GenericModelClientOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val apiKey: JsonField, - private val baseUrl: JsonField, - private val headers: JsonField, - private val providerOptions: JsonField, - private val skipApiKeyFallback: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("apiKey") - @ExcludeMissing - apiKey: JsonField = JsonMissing.of(), - @JsonProperty("baseURL") - @ExcludeMissing - baseUrl: JsonField = JsonMissing.of(), - @JsonProperty("headers") - @ExcludeMissing - headers: JsonField = JsonMissing.of(), - @JsonProperty("providerOptions") - @ExcludeMissing - providerOptions: JsonField = JsonMissing.of(), - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - skipApiKeyFallback: JsonField = JsonMissing.of(), - ) : this(apiKey, baseUrl, headers, providerOptions, skipApiKeyFallback, mutableMapOf()) - - /** - * API key for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun apiKey(): Optional = apiKey.getOptional("apiKey") - - /** - * Base URL for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun baseUrl(): Optional = baseUrl.getOptional("baseURL") - - /** - * Custom headers for the model provider - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun headers(): Optional = headers.getOptional("headers") - - /** - * Provider-specific options passed through to the AI SDK provider constructor. For - * Bedrock: { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { - * project, location, googleAuthOptions }. - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun providerOptions(): Optional = - providerOptions.getOptional("providerOptions") - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use this - * when auth is carried through providerOptions instead of an API key. - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun skipApiKeyFallback(): Optional = - skipApiKeyFallback.getOptional("skipApiKeyFallback") - - /** - * Returns the raw JSON value of [apiKey]. - * - * Unlike [apiKey], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("apiKey") @ExcludeMissing fun _apiKey(): JsonField = apiKey - - /** - * Returns the raw JSON value of [baseUrl]. - * - * Unlike [baseUrl], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("baseURL") @ExcludeMissing fun _baseUrl(): JsonField = baseUrl - - /** - * Returns the raw JSON value of [headers]. - * - * Unlike [headers], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("headers") @ExcludeMissing fun _headers(): JsonField = headers - - /** - * Returns the raw JSON value of [providerOptions]. - * - * Unlike [providerOptions], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("providerOptions") - @ExcludeMissing - fun _providerOptions(): JsonField = providerOptions - - /** - * Returns the raw JSON value of [skipApiKeyFallback]. - * - * Unlike [skipApiKeyFallback], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("skipApiKeyFallback") - @ExcludeMissing - fun _skipApiKeyFallback(): JsonField = skipApiKeyFallback - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GenericModelClientOptions]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GenericModelClientOptions]. */ - class Builder internal constructor() { - - private var apiKey: JsonField = JsonMissing.of() - private var baseUrl: JsonField = JsonMissing.of() - private var headers: JsonField = JsonMissing.of() - private var providerOptions: JsonField = JsonMissing.of() - private var skipApiKeyFallback: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(genericModelClientOptions: GenericModelClientOptions) = apply { - apiKey = genericModelClientOptions.apiKey - baseUrl = genericModelClientOptions.baseUrl - headers = genericModelClientOptions.headers - providerOptions = genericModelClientOptions.providerOptions - skipApiKeyFallback = genericModelClientOptions.skipApiKeyFallback - additionalProperties = - genericModelClientOptions.additionalProperties.toMutableMap() - } - - /** API key for the model provider */ - fun apiKey(apiKey: String) = apiKey(JsonField.of(apiKey)) - - /** - * Sets [Builder.apiKey] to an arbitrary JSON value. - * - * You should usually call [Builder.apiKey] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun apiKey(apiKey: JsonField) = apply { this.apiKey = apiKey } - - /** Base URL for the model provider */ - fun baseUrl(baseUrl: String) = baseUrl(JsonField.of(baseUrl)) - - /** - * Sets [Builder.baseUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.baseUrl] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun baseUrl(baseUrl: JsonField) = apply { this.baseUrl = baseUrl } - - /** Custom headers for the model provider */ - fun headers(headers: Headers) = headers(JsonField.of(headers)) - - /** - * Sets [Builder.headers] to an arbitrary JSON value. - * - * You should usually call [Builder.headers] with a well-typed [Headers] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun headers(headers: JsonField) = apply { this.headers = headers } - - /** - * Provider-specific options passed through to the AI SDK provider constructor. For - * Bedrock: { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { - * project, location, googleAuthOptions }. - */ - fun providerOptions(providerOptions: ProviderOptions) = - providerOptions(JsonField.of(providerOptions)) - - /** - * Sets [Builder.providerOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.providerOptions] with a well-typed - * [ProviderOptions] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun providerOptions(providerOptions: JsonField) = apply { - this.providerOptions = providerOptions - } - - /** - * Alias for calling [providerOptions] with - * `ProviderOptions.ofBedrockApiKey(bedrockApiKey)`. - */ - fun providerOptions(bedrockApiKey: ProviderOptions.BedrockApiKeyProviderOptions) = - providerOptions(ProviderOptions.ofBedrockApiKey(bedrockApiKey)) - - /** - * Alias for calling [providerOptions] with - * `ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)`. - */ - fun providerOptions( - bedrockAwsCredentials: ProviderOptions.BedrockAwsCredentialsProviderOptions - ) = providerOptions(ProviderOptions.ofBedrockAwsCredentials(bedrockAwsCredentials)) - - /** - * Alias for calling [providerOptions] with - * `ProviderOptions.ofGoogleVertex(googleVertex)`. - */ - fun providerOptions(googleVertex: ProviderOptions.GoogleVertexProviderOptions) = - providerOptions(ProviderOptions.ofGoogleVertex(googleVertex)) - - /** - * When true, hosted sessions will not copy x-model-api-key into model.apiKey. Use - * this when auth is carried through providerOptions instead of an API key. - */ - fun skipApiKeyFallback(skipApiKeyFallback: Boolean) = - skipApiKeyFallback(JsonField.of(skipApiKeyFallback)) - - /** - * Sets [Builder.skipApiKeyFallback] to an arbitrary JSON value. - * - * You should usually call [Builder.skipApiKeyFallback] with a well-typed [Boolean] - * value instead. This method is primarily for setting the field to an undocumented - * or not yet supported value. - */ - fun skipApiKeyFallback(skipApiKeyFallback: JsonField) = apply { - this.skipApiKeyFallback = skipApiKeyFallback - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GenericModelClientOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): GenericModelClientOptions = - GenericModelClientOptions( - apiKey, - baseUrl, - headers, - providerOptions, - skipApiKeyFallback, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): GenericModelClientOptions = apply { - if (validated) { - return@apply - } - - apiKey() - baseUrl() - headers().ifPresent { it.validate() } - providerOptions().ifPresent { it.validate() } - skipApiKeyFallback() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (apiKey.asKnown().isPresent) 1 else 0) + - (if (baseUrl.asKnown().isPresent) 1 else 0) + - (headers.asKnown().getOrNull()?.validity() ?: 0) + - (providerOptions.asKnown().getOrNull()?.validity() ?: 0) + - (if (skipApiKeyFallback.asKnown().isPresent) 1 else 0) - - /** Custom headers for the model provider */ - class Headers - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Headers]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Headers]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(headers: Headers) = apply { - additionalProperties = headers.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Headers]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Headers = Headers(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Headers = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Headers && additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = "Headers{additionalProperties=$additionalProperties}" - } - - /** - * Provider-specific options passed through to the AI SDK provider constructor. For - * Bedrock: { region, accessKeyId, secretAccessKey, sessionToken }. For Vertex: { - * project, location, googleAuthOptions }. - */ - @JsonDeserialize(using = ProviderOptions.Deserializer::class) - @JsonSerialize(using = ProviderOptions.Serializer::class) - class ProviderOptions - private constructor( - private val bedrockApiKey: BedrockApiKeyProviderOptions? = null, - private val bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions? = null, - private val googleVertex: GoogleVertexProviderOptions? = null, - private val _json: JsonValue? = null, - ) { - - fun bedrockApiKey(): Optional = - Optional.ofNullable(bedrockApiKey) - - fun bedrockAwsCredentials(): Optional = - Optional.ofNullable(bedrockAwsCredentials) - - fun googleVertex(): Optional = - Optional.ofNullable(googleVertex) - - fun isBedrockApiKey(): Boolean = bedrockApiKey != null - - fun isBedrockAwsCredentials(): Boolean = bedrockAwsCredentials != null - - fun isGoogleVertex(): Boolean = googleVertex != null - - fun asBedrockApiKey(): BedrockApiKeyProviderOptions = - bedrockApiKey.getOrThrow("bedrockApiKey") - - fun asBedrockAwsCredentials(): BedrockAwsCredentialsProviderOptions = - bedrockAwsCredentials.getOrThrow("bedrockAwsCredentials") - - fun asGoogleVertex(): GoogleVertexProviderOptions = - googleVertex.getOrThrow("googleVertex") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - bedrockApiKey != null -> visitor.visitBedrockApiKey(bedrockApiKey) - bedrockAwsCredentials != null -> - visitor.visitBedrockAwsCredentials(bedrockAwsCredentials) - googleVertex != null -> visitor.visitGoogleVertex(googleVertex) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): ProviderOptions = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitBedrockApiKey( - bedrockApiKey: BedrockApiKeyProviderOptions - ) { - bedrockApiKey.validate() - } - - override fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ) { - bedrockAwsCredentials.validate() - } - - override fun visitGoogleVertex( - googleVertex: GoogleVertexProviderOptions - ) { - googleVertex.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitBedrockApiKey( - bedrockApiKey: BedrockApiKeyProviderOptions - ) = bedrockApiKey.validity() - - override fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ) = bedrockAwsCredentials.validity() - - override fun visitGoogleVertex( - googleVertex: GoogleVertexProviderOptions - ) = googleVertex.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is ProviderOptions && - bedrockApiKey == other.bedrockApiKey && - bedrockAwsCredentials == other.bedrockAwsCredentials && - googleVertex == other.googleVertex - } - - override fun hashCode(): Int = - Objects.hash(bedrockApiKey, bedrockAwsCredentials, googleVertex) - - override fun toString(): String = - when { - bedrockApiKey != null -> "ProviderOptions{bedrockApiKey=$bedrockApiKey}" - bedrockAwsCredentials != null -> - "ProviderOptions{bedrockAwsCredentials=$bedrockAwsCredentials}" - googleVertex != null -> "ProviderOptions{googleVertex=$googleVertex}" - _json != null -> "ProviderOptions{_unknown=$_json}" - else -> throw IllegalStateException("Invalid ProviderOptions") - } - - companion object { - - @JvmStatic - fun ofBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions) = - ProviderOptions(bedrockApiKey = bedrockApiKey) - - @JvmStatic - fun ofBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ) = ProviderOptions(bedrockAwsCredentials = bedrockAwsCredentials) - - @JvmStatic - fun ofGoogleVertex(googleVertex: GoogleVertexProviderOptions) = - ProviderOptions(googleVertex = googleVertex) - } - - /** - * An interface that defines how to map each variant of [ProviderOptions] to a value - * of type [T]. - */ - interface Visitor { - - fun visitBedrockApiKey(bedrockApiKey: BedrockApiKeyProviderOptions): T - - fun visitBedrockAwsCredentials( - bedrockAwsCredentials: BedrockAwsCredentialsProviderOptions - ): T - - fun visitGoogleVertex(googleVertex: GoogleVertexProviderOptions): T - - /** - * Maps an unknown variant of [ProviderOptions] to a value of type [T]. - * - * An instance of [ProviderOptions] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, if - * the SDK is on an older version than the API, then the API may respond with - * new variants that the SDK is unaware of. - * - * @throws StagehandInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw StagehandInvalidDataException("Unknown ProviderOptions: $json") - } - } - - internal class Deserializer : - BaseDeserializer(ProviderOptions::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): ProviderOptions { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize( - node, - jacksonTypeRef(), - ) - ?.let { ProviderOptions(bedrockApiKey = it, _json = json) }, - tryDeserialize( - node, - jacksonTypeRef(), - ) - ?.let { - ProviderOptions( - bedrockAwsCredentials = it, - _json = json, - ) - }, - tryDeserialize( - node, - jacksonTypeRef(), - ) - ?.let { ProviderOptions(googleVertex = it, _json = json) }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing from - // boolean). - 0 -> ProviderOptions(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use - // the first completely valid match, or simply the first match if none - // are completely valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : - BaseSerializer(ProviderOptions::class) { - - override fun serialize( - value: ProviderOptions, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.bedrockApiKey != null -> - generator.writeObject(value.bedrockApiKey) - value.bedrockAwsCredentials != null -> - generator.writeObject(value.bedrockAwsCredentials) - value.googleVertex != null -> generator.writeObject(value.googleVertex) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid ProviderOptions") - } - } - } - - class BedrockApiKeyProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val region: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("region") - @ExcludeMissing - region: JsonField = JsonMissing.of() - ) : this(region, mutableMapOf()) - - /** - * AWS region for Amazon Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded with - * an unexpected value). - */ - fun region(): String = region.getRequired("region") - - /** - * Returns the raw JSON value of [region]. - * - * Unlike [region], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("region") - @ExcludeMissing - fun _region(): JsonField = region - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [BedrockApiKeyProviderOptions]. - * - * The following fields are required: - * ```java - * .region() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [BedrockApiKeyProviderOptions]. */ - class Builder internal constructor() { - - private var region: JsonField? = null - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from( - bedrockApiKeyProviderOptions: BedrockApiKeyProviderOptions - ) = apply { - region = bedrockApiKeyProviderOptions.region - additionalProperties = - bedrockApiKeyProviderOptions.additionalProperties.toMutableMap() - } - - /** AWS region for Amazon Bedrock */ - fun region(region: String) = region(JsonField.of(region)) - - /** - * Sets [Builder.region] to an arbitrary JSON value. - * - * You should usually call [Builder.region] with a well-typed [String] value - * instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun region(region: JsonField) = apply { this.region = region } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [BedrockApiKeyProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .region() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): BedrockApiKeyProviderOptions = - BedrockApiKeyProviderOptions( - checkRequired("region", region), - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): BedrockApiKeyProviderOptions = apply { - if (validated) { - return@apply - } - - region() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (if (region.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BedrockApiKeyProviderOptions && - region == other.region && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(region, additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "BedrockApiKeyProviderOptions{region=$region, additionalProperties=$additionalProperties}" - } - - class BedrockAwsCredentialsProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val accessKeyId: JsonField, - private val region: JsonField, - private val secretAccessKey: JsonField, - private val sessionToken: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("accessKeyId") - @ExcludeMissing - accessKeyId: JsonField = JsonMissing.of(), - @JsonProperty("region") - @ExcludeMissing - region: JsonField = JsonMissing.of(), - @JsonProperty("secretAccessKey") - @ExcludeMissing - secretAccessKey: JsonField = JsonMissing.of(), - @JsonProperty("sessionToken") - @ExcludeMissing - sessionToken: JsonField = JsonMissing.of(), - ) : this(accessKeyId, region, secretAccessKey, sessionToken, mutableMapOf()) - - /** - * AWS access key ID for Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded with - * an unexpected value). - */ - fun accessKeyId(): String = accessKeyId.getRequired("accessKeyId") - - /** - * AWS region for Amazon Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded with - * an unexpected value). - */ - fun region(): String = region.getRequired("region") - - /** - * AWS secret access key for Bedrock - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded with - * an unexpected value). - */ - fun secretAccessKey(): String = secretAccessKey.getRequired("secretAccessKey") - - /** - * Optional AWS session token for temporary credentials - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun sessionToken(): Optional = sessionToken.getOptional("sessionToken") - - /** - * Returns the raw JSON value of [accessKeyId]. - * - * Unlike [accessKeyId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("accessKeyId") - @ExcludeMissing - fun _accessKeyId(): JsonField = accessKeyId - - /** - * Returns the raw JSON value of [region]. - * - * Unlike [region], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("region") - @ExcludeMissing - fun _region(): JsonField = region - - /** - * Returns the raw JSON value of [secretAccessKey]. - * - * Unlike [secretAccessKey], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("secretAccessKey") - @ExcludeMissing - fun _secretAccessKey(): JsonField = secretAccessKey - - /** - * Returns the raw JSON value of [sessionToken]. - * - * Unlike [sessionToken], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("sessionToken") - @ExcludeMissing - fun _sessionToken(): JsonField = sessionToken - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [BedrockAwsCredentialsProviderOptions]. - * - * The following fields are required: - * ```java - * .accessKeyId() - * .region() - * .secretAccessKey() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [BedrockAwsCredentialsProviderOptions]. */ - class Builder internal constructor() { - - private var accessKeyId: JsonField? = null - private var region: JsonField? = null - private var secretAccessKey: JsonField? = null - private var sessionToken: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from( - bedrockAwsCredentialsProviderOptions: - BedrockAwsCredentialsProviderOptions - ) = apply { - accessKeyId = bedrockAwsCredentialsProviderOptions.accessKeyId - region = bedrockAwsCredentialsProviderOptions.region - secretAccessKey = bedrockAwsCredentialsProviderOptions.secretAccessKey - sessionToken = bedrockAwsCredentialsProviderOptions.sessionToken - additionalProperties = - bedrockAwsCredentialsProviderOptions.additionalProperties - .toMutableMap() - } - - /** AWS access key ID for Bedrock */ - fun accessKeyId(accessKeyId: String) = - accessKeyId(JsonField.of(accessKeyId)) - - /** - * Sets [Builder.accessKeyId] to an arbitrary JSON value. - * - * You should usually call [Builder.accessKeyId] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun accessKeyId(accessKeyId: JsonField) = apply { - this.accessKeyId = accessKeyId - } - - /** AWS region for Amazon Bedrock */ - fun region(region: String) = region(JsonField.of(region)) - - /** - * Sets [Builder.region] to an arbitrary JSON value. - * - * You should usually call [Builder.region] with a well-typed [String] value - * instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun region(region: JsonField) = apply { this.region = region } - - /** AWS secret access key for Bedrock */ - fun secretAccessKey(secretAccessKey: String) = - secretAccessKey(JsonField.of(secretAccessKey)) - - /** - * Sets [Builder.secretAccessKey] to an arbitrary JSON value. - * - * You should usually call [Builder.secretAccessKey] with a well-typed - * [String] value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. - */ - fun secretAccessKey(secretAccessKey: JsonField) = apply { - this.secretAccessKey = secretAccessKey - } - - /** Optional AWS session token for temporary credentials */ - fun sessionToken(sessionToken: String) = - sessionToken(JsonField.of(sessionToken)) - - /** - * Sets [Builder.sessionToken] to an arbitrary JSON value. - * - * You should usually call [Builder.sessionToken] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun sessionToken(sessionToken: JsonField) = apply { - this.sessionToken = sessionToken - } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [BedrockAwsCredentialsProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .accessKeyId() - * .region() - * .secretAccessKey() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): BedrockAwsCredentialsProviderOptions = - BedrockAwsCredentialsProviderOptions( - checkRequired("accessKeyId", accessKeyId), - checkRequired("region", region), - checkRequired("secretAccessKey", secretAccessKey), - sessionToken, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): BedrockAwsCredentialsProviderOptions = apply { - if (validated) { - return@apply - } - - accessKeyId() - region() - secretAccessKey() - sessionToken() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (accessKeyId.asKnown().isPresent) 1 else 0) + - (if (region.asKnown().isPresent) 1 else 0) + - (if (secretAccessKey.asKnown().isPresent) 1 else 0) + - (if (sessionToken.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is BedrockAwsCredentialsProviderOptions && - accessKeyId == other.accessKeyId && - region == other.region && - secretAccessKey == other.secretAccessKey && - sessionToken == other.sessionToken && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - accessKeyId, - region, - secretAccessKey, - sessionToken, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "BedrockAwsCredentialsProviderOptions{accessKeyId=$accessKeyId, region=$region, secretAccessKey=$secretAccessKey, sessionToken=$sessionToken, additionalProperties=$additionalProperties}" - } - - class GoogleVertexProviderOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val googleAuthOptions: JsonField, - private val headers: JsonField, - private val location: JsonField, - private val project: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("googleAuthOptions") - @ExcludeMissing - googleAuthOptions: JsonField = JsonMissing.of(), - @JsonProperty("headers") - @ExcludeMissing - headers: JsonField = JsonMissing.of(), - @JsonProperty("location") - @ExcludeMissing - location: JsonField = JsonMissing.of(), - @JsonProperty("project") - @ExcludeMissing - project: JsonField = JsonMissing.of(), - ) : this(googleAuthOptions, headers, location, project, mutableMapOf()) - - /** - * Optional Google auth options for Vertex AI - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun googleAuthOptions(): Optional = - googleAuthOptions.getOptional("googleAuthOptions") - - /** - * Custom headers for Vertex AI requests - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun headers(): Optional = headers.getOptional("headers") - - /** - * Google Cloud location for Vertex AI - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun location(): Optional = location.getOptional("location") - - /** - * Google Cloud project ID for Vertex AI - * - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun project(): Optional = project.getOptional("project") - - /** - * Returns the raw JSON value of [googleAuthOptions]. - * - * Unlike [googleAuthOptions], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("googleAuthOptions") - @ExcludeMissing - fun _googleAuthOptions(): JsonField = googleAuthOptions - - /** - * Returns the raw JSON value of [headers]. - * - * Unlike [headers], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("headers") - @ExcludeMissing - fun _headers(): JsonField = headers - - /** - * Returns the raw JSON value of [location]. - * - * Unlike [location], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("location") - @ExcludeMissing - fun _location(): JsonField = location - - /** - * Returns the raw JSON value of [project]. - * - * Unlike [project], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("project") - @ExcludeMissing - fun _project(): JsonField = project - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GoogleVertexProviderOptions]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GoogleVertexProviderOptions]. */ - class Builder internal constructor() { - - private var googleAuthOptions: JsonField = - JsonMissing.of() - private var headers: JsonField = JsonMissing.of() - private var location: JsonField = JsonMissing.of() - private var project: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from( - googleVertexProviderOptions: GoogleVertexProviderOptions - ) = apply { - googleAuthOptions = googleVertexProviderOptions.googleAuthOptions - headers = googleVertexProviderOptions.headers - location = googleVertexProviderOptions.location - project = googleVertexProviderOptions.project - additionalProperties = - googleVertexProviderOptions.additionalProperties.toMutableMap() - } - - /** Optional Google auth options for Vertex AI */ - fun googleAuthOptions(googleAuthOptions: GoogleAuthOptions) = - googleAuthOptions(JsonField.of(googleAuthOptions)) - - /** - * Sets [Builder.googleAuthOptions] to an arbitrary JSON value. - * - * You should usually call [Builder.googleAuthOptions] with a well-typed - * [GoogleAuthOptions] value instead. This method is primarily for setting - * the field to an undocumented or not yet supported value. - */ - fun googleAuthOptions(googleAuthOptions: JsonField) = - apply { - this.googleAuthOptions = googleAuthOptions - } - - /** Custom headers for Vertex AI requests */ - fun headers(headers: Headers) = headers(JsonField.of(headers)) - - /** - * Sets [Builder.headers] to an arbitrary JSON value. - * - * You should usually call [Builder.headers] with a well-typed [Headers] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun headers(headers: JsonField) = apply { this.headers = headers } - - /** Google Cloud location for Vertex AI */ - fun location(location: String) = location(JsonField.of(location)) - - /** - * Sets [Builder.location] to an arbitrary JSON value. - * - * You should usually call [Builder.location] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun location(location: JsonField) = apply { - this.location = location - } - - /** Google Cloud project ID for Vertex AI */ - fun project(project: String) = project(JsonField.of(project)) - - /** - * Sets [Builder.project] to an arbitrary JSON value. - * - * You should usually call [Builder.project] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun project(project: JsonField) = apply { this.project = project } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GoogleVertexProviderOptions]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): GoogleVertexProviderOptions = - GoogleVertexProviderOptions( - googleAuthOptions, - headers, - location, - project, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): GoogleVertexProviderOptions = apply { - if (validated) { - return@apply - } - - googleAuthOptions().ifPresent { it.validate() } - headers().ifPresent { it.validate() } - location() - project() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (googleAuthOptions.asKnown().getOrNull()?.validity() ?: 0) + - (headers.asKnown().getOrNull()?.validity() ?: 0) + - (if (location.asKnown().isPresent) 1 else 0) + - (if (project.asKnown().isPresent) 1 else 0) - - /** Optional Google auth options for Vertex AI */ - class GoogleAuthOptions - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val credentials: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("credentials") - @ExcludeMissing - credentials: JsonField = JsonMissing.of() - ) : this(credentials, mutableMapOf()) - - /** - * @throws StagehandInvalidDataException if the JSON field has an unexpected - * type (e.g. if the server responded with an unexpected value). - */ - fun credentials(): Optional = - credentials.getOptional("credentials") - - /** - * Returns the raw JSON value of [credentials]. - * - * Unlike [credentials], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("credentials") - @ExcludeMissing - fun _credentials(): JsonField = credentials - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [GoogleAuthOptions]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [GoogleAuthOptions]. */ - class Builder internal constructor() { - - private var credentials: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(googleAuthOptions: GoogleAuthOptions) = apply { - credentials = googleAuthOptions.credentials - additionalProperties = - googleAuthOptions.additionalProperties.toMutableMap() - } - - fun credentials(credentials: Credentials) = - credentials(JsonField.of(credentials)) - - /** - * Sets [Builder.credentials] to an arbitrary JSON value. - * - * You should usually call [Builder.credentials] with a well-typed - * [Credentials] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun credentials(credentials: JsonField) = apply { - this.credentials = credentials - } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [GoogleAuthOptions]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - */ - fun build(): GoogleAuthOptions = - GoogleAuthOptions(credentials, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): GoogleAuthOptions = apply { - if (validated) { - return@apply - } - - credentials().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (credentials.asKnown().getOrNull()?.validity() ?: 0) - - class Credentials - @JsonCreator(mode = JsonCreator.Mode.DISABLED) - private constructor( - private val authProviderX509CertUrl: JsonField, - private val authUri: JsonField, - private val clientEmail: JsonField, - private val clientId: JsonField, - private val clientX509CertUrl: JsonField, - private val privateKey: JsonField, - private val privateKeyId: JsonField, - private val projectId: JsonField, - private val tokenUri: JsonField, - private val type: JsonField, - private val universeDomain: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("auth_provider_x509_cert_url") - @ExcludeMissing - authProviderX509CertUrl: JsonField = JsonMissing.of(), - @JsonProperty("auth_uri") - @ExcludeMissing - authUri: JsonField = JsonMissing.of(), - @JsonProperty("client_email") - @ExcludeMissing - clientEmail: JsonField = JsonMissing.of(), - @JsonProperty("client_id") - @ExcludeMissing - clientId: JsonField = JsonMissing.of(), - @JsonProperty("client_x509_cert_url") - @ExcludeMissing - clientX509CertUrl: JsonField = JsonMissing.of(), - @JsonProperty("private_key") - @ExcludeMissing - privateKey: JsonField = JsonMissing.of(), - @JsonProperty("private_key_id") - @ExcludeMissing - privateKeyId: JsonField = JsonMissing.of(), - @JsonProperty("project_id") - @ExcludeMissing - projectId: JsonField = JsonMissing.of(), - @JsonProperty("token_uri") - @ExcludeMissing - tokenUri: JsonField = JsonMissing.of(), - @JsonProperty("type") - @ExcludeMissing - type: JsonField = JsonMissing.of(), - @JsonProperty("universe_domain") - @ExcludeMissing - universeDomain: JsonField = JsonMissing.of(), - ) : this( - authProviderX509CertUrl, - authUri, - clientEmail, - clientId, - clientX509CertUrl, - privateKey, - privateKeyId, - projectId, - tokenUri, - type, - universeDomain, - mutableMapOf(), - ) - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun authProviderX509CertUrl(): Optional = - authProviderX509CertUrl.getOptional("auth_provider_x509_cert_url") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun authUri(): Optional = authUri.getOptional("auth_uri") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun clientEmail(): Optional = - clientEmail.getOptional("client_email") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun clientId(): Optional = clientId.getOptional("client_id") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun clientX509CertUrl(): Optional = - clientX509CertUrl.getOptional("client_x509_cert_url") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun privateKey(): Optional = - privateKey.getOptional("private_key") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun privateKeyId(): Optional = - privateKeyId.getOptional("private_key_id") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun projectId(): Optional = projectId.getOptional("project_id") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun tokenUri(): Optional = tokenUri.getOptional("token_uri") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun type(): Optional = type.getOptional("type") - - /** - * @throws StagehandInvalidDataException if the JSON field has an - * unexpected type (e.g. if the server responded with an unexpected - * value). - */ - fun universeDomain(): Optional = - universeDomain.getOptional("universe_domain") - - /** - * Returns the raw JSON value of [authProviderX509CertUrl]. - * - * Unlike [authProviderX509CertUrl], this method doesn't throw if the - * JSON field has an unexpected type. - */ - @JsonProperty("auth_provider_x509_cert_url") - @ExcludeMissing - fun _authProviderX509CertUrl(): JsonField = - authProviderX509CertUrl - - /** - * Returns the raw JSON value of [authUri]. - * - * Unlike [authUri], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("auth_uri") - @ExcludeMissing - fun _authUri(): JsonField = authUri - - /** - * Returns the raw JSON value of [clientEmail]. - * - * Unlike [clientEmail], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("client_email") - @ExcludeMissing - fun _clientEmail(): JsonField = clientEmail - - /** - * Returns the raw JSON value of [clientId]. - * - * Unlike [clientId], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("client_id") - @ExcludeMissing - fun _clientId(): JsonField = clientId - - /** - * Returns the raw JSON value of [clientX509CertUrl]. - * - * Unlike [clientX509CertUrl], this method doesn't throw if the JSON - * field has an unexpected type. - */ - @JsonProperty("client_x509_cert_url") - @ExcludeMissing - fun _clientX509CertUrl(): JsonField = clientX509CertUrl - - /** - * Returns the raw JSON value of [privateKey]. - * - * Unlike [privateKey], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("private_key") - @ExcludeMissing - fun _privateKey(): JsonField = privateKey - - /** - * Returns the raw JSON value of [privateKeyId]. - * - * Unlike [privateKeyId], this method doesn't throw if the JSON field - * has an unexpected type. - */ - @JsonProperty("private_key_id") - @ExcludeMissing - fun _privateKeyId(): JsonField = privateKeyId - - /** - * Returns the raw JSON value of [projectId]. - * - * Unlike [projectId], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("project_id") - @ExcludeMissing - fun _projectId(): JsonField = projectId - - /** - * Returns the raw JSON value of [tokenUri]. - * - * Unlike [tokenUri], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("token_uri") - @ExcludeMissing - fun _tokenUri(): JsonField = tokenUri - - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("type") - @ExcludeMissing - fun _type(): JsonField = type - - /** - * Returns the raw JSON value of [universeDomain]. - * - * Unlike [universeDomain], this method doesn't throw if the JSON field - * has an unexpected type. - */ - @JsonProperty("universe_domain") - @ExcludeMissing - fun _universeDomain(): JsonField = universeDomain - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [Credentials]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Credentials]. */ - class Builder internal constructor() { - - private var authProviderX509CertUrl: JsonField = - JsonMissing.of() - private var authUri: JsonField = JsonMissing.of() - private var clientEmail: JsonField = JsonMissing.of() - private var clientId: JsonField = JsonMissing.of() - private var clientX509CertUrl: JsonField = JsonMissing.of() - private var privateKey: JsonField = JsonMissing.of() - private var privateKeyId: JsonField = JsonMissing.of() - private var projectId: JsonField = JsonMissing.of() - private var tokenUri: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() - private var universeDomain: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(credentials: Credentials) = apply { - authProviderX509CertUrl = credentials.authProviderX509CertUrl - authUri = credentials.authUri - clientEmail = credentials.clientEmail - clientId = credentials.clientId - clientX509CertUrl = credentials.clientX509CertUrl - privateKey = credentials.privateKey - privateKeyId = credentials.privateKeyId - projectId = credentials.projectId - tokenUri = credentials.tokenUri - type = credentials.type - universeDomain = credentials.universeDomain - additionalProperties = - credentials.additionalProperties.toMutableMap() - } - - fun authProviderX509CertUrl(authProviderX509CertUrl: String) = - authProviderX509CertUrl(JsonField.of(authProviderX509CertUrl)) - - /** - * Sets [Builder.authProviderX509CertUrl] to an arbitrary JSON - * value. - * - * You should usually call [Builder.authProviderX509CertUrl] with a - * well-typed [String] value instead. This method is primarily for - * setting the field to an undocumented or not yet supported value. - */ - fun authProviderX509CertUrl( - authProviderX509CertUrl: JsonField - ) = apply { this.authProviderX509CertUrl = authProviderX509CertUrl } - - fun authUri(authUri: String) = authUri(JsonField.of(authUri)) - - /** - * Sets [Builder.authUri] to an arbitrary JSON value. - * - * You should usually call [Builder.authUri] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun authUri(authUri: JsonField) = apply { - this.authUri = authUri - } - - fun clientEmail(clientEmail: String) = - clientEmail(JsonField.of(clientEmail)) - - /** - * Sets [Builder.clientEmail] to an arbitrary JSON value. - * - * You should usually call [Builder.clientEmail] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun clientEmail(clientEmail: JsonField) = apply { - this.clientEmail = clientEmail - } - - fun clientId(clientId: String) = clientId(JsonField.of(clientId)) - - /** - * Sets [Builder.clientId] to an arbitrary JSON value. - * - * You should usually call [Builder.clientId] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun clientId(clientId: JsonField) = apply { - this.clientId = clientId - } - - fun clientX509CertUrl(clientX509CertUrl: String) = - clientX509CertUrl(JsonField.of(clientX509CertUrl)) - - /** - * Sets [Builder.clientX509CertUrl] to an arbitrary JSON value. - * - * You should usually call [Builder.clientX509CertUrl] with a - * well-typed [String] value instead. This method is primarily for - * setting the field to an undocumented or not yet supported value. - */ - fun clientX509CertUrl(clientX509CertUrl: JsonField) = - apply { - this.clientX509CertUrl = clientX509CertUrl - } - - fun privateKey(privateKey: String) = - privateKey(JsonField.of(privateKey)) - - /** - * Sets [Builder.privateKey] to an arbitrary JSON value. - * - * You should usually call [Builder.privateKey] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun privateKey(privateKey: JsonField) = apply { - this.privateKey = privateKey - } - - fun privateKeyId(privateKeyId: String) = - privateKeyId(JsonField.of(privateKeyId)) - - /** - * Sets [Builder.privateKeyId] to an arbitrary JSON value. - * - * You should usually call [Builder.privateKeyId] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun privateKeyId(privateKeyId: JsonField) = apply { - this.privateKeyId = privateKeyId - } - - fun projectId(projectId: String) = - projectId(JsonField.of(projectId)) - - /** - * Sets [Builder.projectId] to an arbitrary JSON value. - * - * You should usually call [Builder.projectId] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun projectId(projectId: JsonField) = apply { - this.projectId = projectId - } - - fun tokenUri(tokenUri: String) = tokenUri(JsonField.of(tokenUri)) - - /** - * Sets [Builder.tokenUri] to an arbitrary JSON value. - * - * You should usually call [Builder.tokenUri] with a well-typed - * [String] value instead. This method is primarily for setting the - * field to an undocumented or not yet supported value. - */ - fun tokenUri(tokenUri: JsonField) = apply { - this.tokenUri = tokenUri - } - - fun type(type: String) = type(JsonField.of(type)) - - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [String] - * value instead. This method is primarily for setting the field to - * an undocumented or not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } - - fun universeDomain(universeDomain: String) = - universeDomain(JsonField.of(universeDomain)) - - /** - * Sets [Builder.universeDomain] to an arbitrary JSON value. - * - * You should usually call [Builder.universeDomain] with a - * well-typed [String] value instead. This method is primarily for - * setting the field to an undocumented or not yet supported value. - */ - fun universeDomain(universeDomain: JsonField) = apply { - this.universeDomain = universeDomain - } - - fun additionalProperties( - additionalProperties: Map - ) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Credentials]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - */ - fun build(): Credentials = - Credentials( - authProviderX509CertUrl, - authUri, - clientEmail, - clientId, - clientX509CertUrl, - privateKey, - privateKeyId, - projectId, - tokenUri, - type, - universeDomain, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Credentials = apply { - if (validated) { - return@apply - } - - authProviderX509CertUrl() - authUri() - clientEmail() - clientId() - clientX509CertUrl() - privateKey() - privateKeyId() - projectId() - tokenUri() - type() - universeDomain() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in - * this object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (authProviderX509CertUrl.asKnown().isPresent) 1 else 0) + - (if (authUri.asKnown().isPresent) 1 else 0) + - (if (clientEmail.asKnown().isPresent) 1 else 0) + - (if (clientId.asKnown().isPresent) 1 else 0) + - (if (clientX509CertUrl.asKnown().isPresent) 1 else 0) + - (if (privateKey.asKnown().isPresent) 1 else 0) + - (if (privateKeyId.asKnown().isPresent) 1 else 0) + - (if (projectId.asKnown().isPresent) 1 else 0) + - (if (tokenUri.asKnown().isPresent) 1 else 0) + - (if (type.asKnown().isPresent) 1 else 0) + - (if (universeDomain.asKnown().isPresent) 1 else 0) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Credentials && - authProviderX509CertUrl == other.authProviderX509CertUrl && - authUri == other.authUri && - clientEmail == other.clientEmail && - clientId == other.clientId && - clientX509CertUrl == other.clientX509CertUrl && - privateKey == other.privateKey && - privateKeyId == other.privateKeyId && - projectId == other.projectId && - tokenUri == other.tokenUri && - type == other.type && - universeDomain == other.universeDomain && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - authProviderX509CertUrl, - authUri, - clientEmail, - clientId, - clientX509CertUrl, - privateKey, - privateKeyId, - projectId, - tokenUri, - type, - universeDomain, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Credentials{authProviderX509CertUrl=$authProviderX509CertUrl, authUri=$authUri, clientEmail=$clientEmail, clientId=$clientId, clientX509CertUrl=$clientX509CertUrl, privateKey=$privateKey, privateKeyId=$privateKeyId, projectId=$projectId, tokenUri=$tokenUri, type=$type, universeDomain=$universeDomain, additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GoogleAuthOptions && - credentials == other.credentials && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash(credentials, additionalProperties) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GoogleAuthOptions{credentials=$credentials, additionalProperties=$additionalProperties}" - } - - /** Custom headers for Vertex AI requests */ - class Headers - @JsonCreator - private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map - ) { - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Headers]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Headers]. */ - class Builder internal constructor() { - - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(headers: Headers) = apply { - additionalProperties = headers.additionalProperties.toMutableMap() - } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Headers]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - */ - fun build(): Headers = Headers(additionalProperties.toImmutable()) - } - - private var validated: Boolean = false - - fun validate(): Headers = apply { - if (validated) { - return@apply - } - - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: StagehandInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Headers && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Headers{additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GoogleVertexProviderOptions && - googleAuthOptions == other.googleAuthOptions && - headers == other.headers && - location == other.location && - project == other.project && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - googleAuthOptions, - headers, - location, - project, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GoogleVertexProviderOptions{googleAuthOptions=$googleAuthOptions, headers=$headers, location=$location, project=$project, additionalProperties=$additionalProperties}" - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is GenericModelClientOptions && - apiKey == other.apiKey && - baseUrl == other.baseUrl && - headers == other.headers && - providerOptions == other.providerOptions && - skipApiKeyFallback == other.skipApiKeyFallback && - additionalProperties == other.additionalProperties - } - - private val hashCode: Int by lazy { - Objects.hash( - apiKey, - baseUrl, - headers, - providerOptions, - skipApiKeyFallback, - additionalProperties, - ) - } - - override fun hashCode(): Int = hashCode - - override fun toString() = - "GenericModelClientOptions{apiKey=$apiKey, baseUrl=$baseUrl, headers=$headers, providerOptions=$providerOptions, skipApiKeyFallback=$skipApiKeyFallback, additionalProperties=$additionalProperties}" - } - } - /** Logging verbosity level (0=quiet, 1=normal, 2=debug) */ class Verbose @JsonCreator private constructor(private val value: JsonField) : Enum { diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt index 443104b..4584374 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -30,8 +30,8 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * Server-Sent Event emitted during streaming responses. Events are sent as `data: \n\n`. Key - * order: data (with status first), type, id. + * Server-Sent Event emitted during streaming responses. Events are sent as `event: \ndata: + * \n\n`, where the JSON payload has the shape `{ data, type, id }`. */ class StreamEvent @JsonCreator(mode = JsonCreator.Mode.DISABLED) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt index 1326d37..6e3b3d0 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/ModelConfigTest.kt @@ -14,42 +14,27 @@ internal class ModelConfigTest { fun create() { val modelConfig = ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() - assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5-nano") + assertThat(modelConfig.modelName()).isEqualTo("openai/gpt-5.4-mini") assertThat(modelConfig.apiKey()).contains("sk-some-openai-api-key") assertThat(modelConfig.baseUrl()).contains("https://api.openai.com/v1") assertThat(modelConfig.headers()) .contains( ModelConfig.Headers.builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) assertThat(modelConfig.provider()).contains(ModelConfig.Provider.OPENAI) - assertThat(modelConfig.providerOptions()) - .contains( - ModelConfig.ProviderOptions.ofBedrockApiKey( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - ) - assertThat(modelConfig.skipApiKeyFallback()).contains(true) } @Test @@ -57,21 +42,15 @@ internal class ModelConfigTest { val jsonMapper = jsonMapper() val modelConfig = ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() val roundtrippedModelConfig = diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt index ac1315c..31ef59b 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionActParamsTest.kt @@ -20,24 +20,15 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -85,25 +76,15 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -155,25 +136,15 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -205,24 +176,15 @@ internal class SessionActParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index e2c6f96..f040cad 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -19,47 +19,29 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -73,6 +55,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -111,49 +95,29 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -167,6 +131,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -209,49 +175,29 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -265,6 +211,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -279,47 +227,29 @@ internal class SessionExecuteParamsTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -334,6 +264,8 @@ internal class SessionExecuteParamsTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) assertThat(body.frameId()).contains("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index f14f0a4..d84a3f9 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -20,24 +20,15 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -74,25 +65,15 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -133,25 +114,15 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -175,24 +146,15 @@ internal class SessionExtractParamsTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index fc07b50..08f0c13 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -20,24 +20,15 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -83,25 +74,15 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -151,25 +132,15 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -201,24 +172,15 @@ internal class SessionObserveParamsTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions.builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt index 0d05eca..0a8dffc 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionStartParamsTest.kt @@ -159,27 +159,6 @@ internal class SessionStartParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -344,27 +323,6 @@ internal class SessionStartParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -542,27 +500,6 @@ internal class SessionStartParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -719,30 +656,6 @@ internal class SessionStartParamsTest { assertThat(body.browserbaseSessionId()).contains("browserbaseSessionID") assertThat(body.domSettleTimeoutMs()).contains(5000.0) assertThat(body.experimental()).contains(true) - assertThat(body.modelClientOptions()) - .contains( - SessionStartParams.ModelClientOptions.ofBedrockApiKey( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) - ) assertThat(body.selfHeal()).contains(true) assertThat(body.systemPrompt()).contains("systemPrompt") assertThat(body.verbose()).contains(SessionStartParams.Verbose._1) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt index fce6e48..6941c36 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ErrorHandlingTest.kt @@ -242,33 +242,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -464,33 +437,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -686,33 +632,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -908,33 +827,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1130,33 +1022,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1352,33 +1217,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1574,33 +1412,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -1796,33 +1607,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2018,33 +1802,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2240,33 +1997,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2462,33 +2192,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2684,33 +2387,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -2906,33 +2582,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -3128,33 +2777,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -3350,33 +2972,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -3572,33 +3167,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -3792,33 +3360,6 @@ internal class ErrorHandlingTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt index b67f63c..392cc05 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/ServiceParamsTest.kt @@ -201,27 +201,6 @@ internal class ServiceParamsTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions.builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty("X-Custom-Header", JsonValue.from("value")) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) @@ -256,25 +235,15 @@ internal class ServiceParamsTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 78f3def..a21bd07 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -40,25 +40,15 @@ internal class SessionServiceAsyncTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -107,25 +97,15 @@ internal class SessionServiceAsyncTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -197,49 +177,29 @@ internal class SessionServiceAsyncTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -253,6 +213,8 @@ internal class SessionServiceAsyncTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -285,49 +247,29 @@ internal class SessionServiceAsyncTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -341,6 +283,8 @@ internal class SessionServiceAsyncTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -375,25 +319,15 @@ internal class SessionServiceAsyncTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -434,25 +368,15 @@ internal class SessionServiceAsyncTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -527,25 +451,15 @@ internal class SessionServiceAsyncTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -595,25 +509,15 @@ internal class SessionServiceAsyncTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -836,33 +740,6 @@ internal class SessionServiceAsyncTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 7d7349d..7923bb5 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -40,25 +40,15 @@ internal class SessionServiceTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -106,25 +96,15 @@ internal class SessionServiceTest { SessionActParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .timeout(30000.0) @@ -195,49 +175,29 @@ internal class SessionServiceTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -251,6 +211,8 @@ internal class SessionServiceTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -282,49 +244,29 @@ internal class SessionServiceTest { .cua(true) .executionModel( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .mode(SessionExecuteParams.AgentConfig.Mode.CUA) .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .provider(SessionExecuteParams.AgentConfig.Provider.OPENAI) @@ -338,6 +280,8 @@ internal class SessionServiceTest { ) .highlightCursor(true) .maxSteps(20.0) + .toolTimeout(30000.0) + .useSearch(true) .build() ) .frameId("frameId") @@ -372,25 +316,15 @@ internal class SessionServiceTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -430,25 +364,15 @@ internal class SessionServiceTest { SessionExtractParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("#main-content") @@ -522,25 +446,15 @@ internal class SessionServiceTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -589,25 +503,15 @@ internal class SessionServiceTest { SessionObserveParams.Options.builder() .model( ModelConfig.builder() - .modelName("openai/gpt-5-nano") + .modelName("openai/gpt-5.4-mini") .apiKey("sk-some-openai-api-key") .baseUrl("https://api.openai.com/v1") .headers( ModelConfig.Headers.builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) + .putAdditionalProperty("foo", JsonValue.from("string")) .build() ) .provider(ModelConfig.Provider.OPENAI) - .providerOptions( - ModelConfig.ProviderOptions.BedrockApiKeyProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .skipApiKeyFallback(true) .build() ) .selector("nav") @@ -829,33 +733,6 @@ internal class SessionServiceTest { .browserbaseSessionId("browserbaseSessionID") .domSettleTimeoutMs(5000.0) .experimental(true) - .modelClientOptions( - SessionStartParams.ModelClientOptions.BedrockApiKeyModelClientOptions - .builder() - .apiKey("bedrock-short-term-api-key") - .providerOptions( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .ProviderOptions - .builder() - .region("us-east-1") - .build() - ) - .baseUrl("https://api.openai.com/v1") - .headers( - SessionStartParams.ModelClientOptions - .BedrockApiKeyModelClientOptions - .Headers - .builder() - .putAdditionalProperty( - "X-Custom-Header", - JsonValue.from("value"), - ) - .build() - ) - .skipApiKeyFallback(true) - .build() - ) .selfHeal(true) .systemPrompt("systemPrompt") .verbose(SessionStartParams.Verbose._1) From f44380d6e8d3f9ced02f220462a6678e925c6b08 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 03:51:35 +0000 Subject: [PATCH 146/164] feat: support setting headers via env --- .../main/kotlin/com/browserbase/api/core/ClientOptions.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index ac6a5ef..77cf224 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -433,6 +433,14 @@ private constructor( (System.getProperty("stagehand.modelApiKey") ?: System.getenv("MODEL_API_KEY"))?.let { modelApiKey(it) } + System.getenv("STAGEHAND_CUSTOM_HEADERS")?.let { customHeadersEnv -> + for (line in customHeadersEnv.split("\n")) { + val colon = line.indexOf(':') + if (colon >= 0) { + putHeader(line.substring(0, colon).trim(), line.substring(colon + 1).trim()) + } + } + } } /** From f0dc4444a45f0ce8d577e138c423773671a949bd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 06:01:13 +0000 Subject: [PATCH 147/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index d8428d4..0bd171d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-1c6caa2891a7f3bdfc0caab143f285badc9145220c9b29cd5e4cf1a9b3ac11cf.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-1c6caa2891a7f3bdfc0caab143f285badc9145220c9b29cd5e4cf1a9b3ac11cf.yml openapi_spec_hash: 28c4b734a5309067c39bb4c4b709b9ab config_hash: a962ae71493deb11a1c903256fb25386 From 60f320b6bc77cbc7530bff21c2f69717260d9a2e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 02:00:20 +0000 Subject: [PATCH 148/164] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 0bd171d..b17eb0a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-1c6caa2891a7f3bdfc0caab143f285badc9145220c9b29cd5e4cf1a9b3ac11cf.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-dbbff1a35360850898f7d60588e257faeac145a73cfcae634cfeb1b70109b6af.yml openapi_spec_hash: 28c4b734a5309067c39bb4c4b709b9ab config_hash: a962ae71493deb11a1c903256fb25386 From 84e5f9f0102615526f72375f0957fea5641fd008 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 02:05:56 +0000 Subject: [PATCH 149/164] docs: clarify forwards compat behavior --- README.md | 4 +- .../client/okhttp/StagehandOkHttpClient.kt | 3 + .../okhttp/StagehandOkHttpClientAsync.kt | 3 + .../com/browserbase/api/core/ClientOptions.kt | 6 + .../browserbase/api/core/RequestOptions.kt | 9 + .../browserbase/api/models/sessions/Action.kt | 8 + .../api/models/sessions/ModelConfig.kt | 26 ++ .../api/models/sessions/SessionActParams.kt | 115 ++++++ .../api/models/sessions/SessionActResponse.kt | 37 ++ .../api/models/sessions/SessionEndParams.kt | 9 + .../api/models/sessions/SessionEndResponse.kt | 8 + .../models/sessions/SessionExecuteParams.kt | 136 +++++++ .../models/sessions/SessionExecuteResponse.kt | 67 ++++ .../models/sessions/SessionExtractParams.kt | 76 ++++ .../models/sessions/SessionExtractResponse.kt | 17 + .../models/sessions/SessionNavigateParams.kt | 37 ++ .../sessions/SessionNavigateResponse.kt | 17 + .../models/sessions/SessionObserveParams.kt | 77 ++++ .../models/sessions/SessionObserveResponse.kt | 27 ++ .../models/sessions/SessionReplayParams.kt | 9 + .../models/sessions/SessionReplayResponse.kt | 67 ++++ .../api/models/sessions/SessionStartParams.kt | 365 ++++++++++++++++++ .../models/sessions/SessionStartResponse.kt | 17 + .../api/models/sessions/StreamEvent.kt | 85 ++++ 24 files changed, 1224 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f65c2e2..e51da24 100644 --- a/README.md +++ b/README.md @@ -687,7 +687,9 @@ In rare cases, the API may return a response that doesn't match the expected typ By default, the SDK will not throw an exception in this case. It will throw [`StagehandInvalidDataException`](stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/StagehandInvalidDataException.kt) only if you directly access the property. -If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: +Validating the response is _not_ forwards compatible with new types from the API for existing fields. + +If you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`: ```java import com.browserbase.api.models.sessions.SessionActResponse; diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index 2137ec6..b5e471d 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -230,6 +230,9 @@ class StagehandOkHttpClient private constructor() { /** * Whether to call `validate` on every response before returning it. * + * Setting this to `true` is _not_ forwards compatible with new types from the API for + * existing fields. + * * Defaults to false, which means the shape of the response will not be validated upfront. * Instead, validation will only occur for the parts of the response that are accessed. */ diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index ffacd17..924c40f 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -230,6 +230,9 @@ class StagehandOkHttpClientAsync private constructor() { /** * Whether to call `validate` on every response before returning it. * + * Setting this to `true` is _not_ forwards compatible with new types from the API for + * existing fields. + * * Defaults to false, which means the shape of the response will not be validated upfront. * Instead, validation will only occur for the parts of the response that are accessed. */ diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 77cf224..6e33f5d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -80,6 +80,9 @@ private constructor( /** * Whether to call `validate` on every response before returning it. * + * Setting this to `true` is _not_ forwards compatible with new types from the API for existing + * fields. + * * Defaults to false, which means the shape of the response will not be validated upfront. * Instead, validation will only occur for the parts of the response that are accessed. */ @@ -270,6 +273,9 @@ private constructor( /** * Whether to call `validate` on every response before returning it. * + * Setting this to `true` is _not_ forwards compatible with new types from the API for + * existing fields. + * * Defaults to false, which means the shape of the response will not be validated upfront. * Instead, validation will only occur for the parts of the response that are accessed. */ diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt index 9674a09..795cdd5 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/RequestOptions.kt @@ -33,6 +33,15 @@ class RequestOptions private constructor(val responseValidation: Boolean?, val t private var responseValidation: Boolean? = null private var timeout: Timeout? = null + /** + * Whether to call `validate` on the response before returning it. + * + * Setting this to `true` is _not_ forwards compatible with new types from the API for + * existing fields. + * + * Defaults to false, which means the shape of the response will not be validated upfront. + * Instead, validation will only occur for the parts of the response that are accessed. + */ fun responseValidation(responseValidation: Boolean) = apply { this.responseValidation = responseValidation } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt index 2ce760b..a77aa3d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/Action.kt @@ -288,6 +288,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Action = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt index 4e46131..b20ac9d 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/ModelConfig.kt @@ -260,6 +260,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): ModelConfig = apply { if (validated) { return@apply @@ -353,6 +361,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Headers = apply { if (validated) { return@apply @@ -502,6 +519,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Provider = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt index 6d92b39..a72cbeb 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActParams.kt @@ -543,6 +543,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Body = apply { if (validated) { return@apply @@ -622,6 +631,35 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, unless + * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of + * the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = input.accept(new Input.Visitor>() { + * @Override + * public Optional visitString(String string) { + * return Optional.of(string.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in [visitor] + * and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { string != null -> visitor.visitString(string) @@ -631,6 +669,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Input = apply { if (validated) { return@apply @@ -945,6 +992,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Options = apply { if (validated) { return@apply @@ -1000,6 +1056,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, + * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this + * version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = model.accept(new Model.Visitor>() { + * @Override + * public Optional visitConfig(ModelConfig config) { + * return Optional.of(config.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { config != null -> visitor.visitConfig(config) @@ -1009,6 +1095,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Model = apply { if (validated) { return@apply @@ -1213,6 +1309,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Variables = apply { if (validated) { return@apply @@ -1370,6 +1476,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt index 62bec51..90bf268 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionActResponse.kt @@ -164,6 +164,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionActResponse = apply { if (validated) { return@apply @@ -332,6 +340,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply @@ -616,6 +633,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Result = apply { if (validated) { return@apply @@ -943,6 +970,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Action = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt index cf9a245..ff13fdc 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndParams.kt @@ -331,6 +331,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt index 3a886e7..d3f370f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionEndResponse.kt @@ -130,6 +130,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionEndResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index f68232a..c850bce 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -616,6 +616,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Body = apply { if (validated) { return@apply @@ -973,6 +982,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): AgentConfig = apply { if (validated) { return@apply @@ -1038,6 +1056,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, + * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this + * version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = executionModel.accept(new ExecutionModel.Visitor>() { + * @Override + * public Optional visitModelConfig(ModelConfig modelConfig) { + * return Optional.of(modelConfig.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { modelConfig != null -> visitor.visitModelConfig(modelConfig) @@ -1047,6 +1095,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): ExecutionModel = apply { if (validated) { return@apply @@ -1288,6 +1346,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Mode = apply { if (validated) { return@apply @@ -1350,6 +1418,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, + * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this + * version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = model.accept(new Model.Visitor>() { + * @Override + * public Optional visitConfig(ModelConfig config) { + * return Optional.of(config.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { config != null -> visitor.visitConfig(config) @@ -1359,6 +1457,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Model = apply { if (validated) { return@apply @@ -1609,6 +1717,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Provider = apply { if (validated) { return@apply @@ -1948,6 +2066,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): ExecuteOptions = apply { if (validated) { return@apply @@ -2108,6 +2235,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt index 9b16655..c2837fc 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteResponse.kt @@ -164,6 +164,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionExecuteResponse = apply { if (validated) { return@apply @@ -339,6 +347,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply @@ -680,6 +697,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Result = apply { if (validated) { return@apply @@ -1095,6 +1122,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Action = apply { if (validated) { return@apply @@ -1234,6 +1271,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Metadata = apply { if (validated) { return@apply @@ -1564,6 +1611,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Usage = apply { if (validated) { return@apply @@ -1807,6 +1864,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): CacheEntry = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index d732dbe..2e7574c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -564,6 +564,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Body = apply { if (validated) { return@apply @@ -789,6 +798,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Options = apply { if (validated) { return@apply @@ -844,6 +862,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, + * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this + * version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = model.accept(new Model.Visitor>() { + * @Override + * public Optional visitConfig(ModelConfig config) { + * return Optional.of(config.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { config != null -> visitor.visitConfig(config) @@ -853,6 +901,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Model = apply { if (validated) { return@apply @@ -1073,6 +1131,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Schema = apply { if (validated) { return@apply @@ -1208,6 +1275,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt index 306abcd..e029256 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractResponse.kt @@ -162,6 +162,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionExtractResponse = apply { if (validated) { return@apply @@ -319,6 +327,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt index d848600..7abd8a2 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateParams.kt @@ -589,6 +589,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Body = apply { if (validated) { return@apply @@ -810,6 +819,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Options = apply { if (validated) { return@apply @@ -941,6 +959,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): WaitUntil = apply { if (validated) { return@apply @@ -1095,6 +1123,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt index 1f6e688..a4ccaa6 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionNavigateResponse.kt @@ -162,6 +162,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionNavigateResponse = apply { if (validated) { return@apply @@ -319,6 +327,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index d18eb4a..8331e8b 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -508,6 +508,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Body = apply { if (validated) { return@apply @@ -771,6 +780,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Options = apply { if (validated) { return@apply @@ -828,6 +846,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, + * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this + * version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = model.accept(new Model.Visitor>() { + * @Override + * public Optional visitConfig(ModelConfig config) { + * return Optional.of(config.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { config != null -> visitor.visitConfig(config) @@ -837,6 +885,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Model = apply { if (validated) { return@apply @@ -1042,6 +1100,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Variables = apply { if (validated) { return@apply @@ -1200,6 +1268,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt index 9c1c551..c28a2b3 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveResponse.kt @@ -164,6 +164,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionObserveResponse = apply { if (validated) { return@apply @@ -352,6 +360,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply @@ -670,6 +687,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Result = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt index 093a776..2d25194 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayParams.kt @@ -297,6 +297,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt index 5ac9a0d..a063510 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionReplayResponse.kt @@ -164,6 +164,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionReplayResponse = apply { if (validated) { return@apply @@ -355,6 +363,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply @@ -623,6 +640,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Page = apply { if (validated) { return@apply @@ -957,6 +984,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Action = apply { if (validated) { return@apply @@ -1058,6 +1095,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Parameters = apply { if (validated) { return@apply @@ -1165,6 +1212,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Result = apply { if (validated) { return@apply @@ -1424,6 +1481,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): TokenUsage = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index 994401f..d940a91 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -1080,6 +1080,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Body = apply { if (validated) { return@apply @@ -1336,6 +1345,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Browser = apply { if (validated) { return@apply @@ -2180,6 +2198,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): LaunchOptions = apply { if (validated) { return@apply @@ -2306,6 +2334,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): CdpHeaders = apply { if (validated) { return@apply @@ -2372,6 +2410,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the + * API, unless [visitor] overrides [Visitor.unknown]. To handle variants not known + * to this version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = ignoreDefaultArgs.accept(new IgnoreDefaultArgs.Visitor>() { + * @Override + * public Optional visitBool(Boolean bool) { + * return Optional.of(bool.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { bool != null -> visitor.visitBool(bool) @@ -2381,6 +2449,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): IgnoreDefaultArgs = apply { if (validated) { return@apply @@ -2746,6 +2824,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Proxy = apply { if (validated) { return@apply @@ -2957,6 +3045,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Viewport = apply { if (validated) { return@apply @@ -3158,6 +3256,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Type = apply { if (validated) { return@apply @@ -3568,6 +3676,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): BrowserbaseSessionCreateParams = apply { if (validated) { return@apply @@ -4151,6 +4268,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): BrowserSettings = apply { if (validated) { return@apply @@ -4353,6 +4480,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Context = apply { if (validated) { return@apply @@ -4748,6 +4885,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Fingerprint = apply { if (validated) { return@apply @@ -4893,6 +5040,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Browser = apply { if (validated) { return@apply @@ -5027,6 +5184,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Device = apply { if (validated) { return@apply @@ -5164,6 +5331,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): HttpVersion = apply { if (validated) { return@apply @@ -5321,6 +5498,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): OperatingSystem = apply { if (validated) { return@apply @@ -5578,6 +5765,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Screen = apply { if (validated) { return@apply @@ -5776,6 +5973,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Os = apply { if (validated) { return@apply @@ -5947,6 +6154,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Viewport = apply { if (validated) { return@apply @@ -6069,6 +6286,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, + * unless [visitor] overrides [Visitor.unknown]. To handle variants not known to this + * version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = proxies.accept(new Proxies.Visitor>() { + * @Override + * public Optional visitBool(Boolean bool) { + * return Optional.of(bool.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { bool != null -> visitor.visitBool(bool) @@ -6078,6 +6325,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Proxies = apply { if (validated) { return@apply @@ -6246,6 +6503,36 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given + * [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the + * API, unless [visitor] overrides [Visitor.unknown]. To handle variants not known + * to this version of the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = proxyConfig.accept(new ProxyConfig.Visitor>() { + * @Override + * public Optional visitBrowserbase(Browserbase browserbase) { + * return Optional.of(browserbase.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { browserbase != null -> visitor.visitBrowserbase(browserbase) @@ -6255,6 +6542,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): ProxyConfig = apply { if (validated) { return@apply @@ -6576,6 +6873,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Browserbase = apply { if (validated) { return@apply @@ -6807,6 +7114,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their + * expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): Geolocation = apply { if (validated) { return@apply @@ -7145,6 +7462,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected + * types recursively. + * + * This method is _not_ forwards compatible with new types from the API for + * existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object + * doesn't match its expected type. + */ fun validate(): External = apply { if (validated) { return@apply @@ -7322,6 +7649,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): Region = apply { if (validated) { return@apply @@ -7421,6 +7758,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): UserMetadata = apply { if (validated) { return@apply @@ -7591,6 +7938,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Verbose = apply { if (validated) { return@apply @@ -7723,6 +8079,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): XStreamResponse = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt index e342e19..423a237 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartResponse.kt @@ -162,6 +162,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): SessionStartResponse = apply { if (validated) { return@apply @@ -379,6 +387,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt index 4584374..3c0b838 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/StreamEvent.kt @@ -225,6 +225,14 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): StreamEvent = apply { if (validated) { return@apply @@ -282,6 +290,35 @@ private constructor( fun _json(): Optional = Optional.ofNullable(_json) + /** + * Maps this instance's current variant to a value of type [T] using the given [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, unless + * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of + * the SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.browserbase.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = data.accept(new Data.Visitor>() { + * @Override + * public Optional visitStreamEventSystemDataOutput(StreamEventSystemDataOutput streamEventSystemDataOutput) { + * return Optional.of(streamEventSystemDataOutput.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws StagehandInvalidDataException if [Visitor.unknown] is not overridden in [visitor] + * and the current variant is unknown. + */ fun accept(visitor: Visitor): T = when { streamEventSystemDataOutput != null -> @@ -293,6 +330,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Data = apply { if (validated) { return@apply @@ -627,6 +673,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): StreamEventSystemDataOutput = apply { if (validated) { return@apply @@ -768,6 +824,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't + * match its expected type. + */ fun validate(): Status = apply { if (validated) { return@apply @@ -982,6 +1048,16 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ fun validate(): StreamEventLogDataOutput = apply { if (validated) { return@apply @@ -1127,6 +1203,15 @@ private constructor( private var validated: Boolean = false + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match its + * expected type. + */ fun validate(): Type = apply { if (validated) { return@apply From 97c024f03e5feacc7f9467df1be2c9ef2e4cf2da Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 02:07:15 +0000 Subject: [PATCH 150/164] feat(client): more robust error parsing --- .../com/browserbase/api/errors/BadRequestException.kt | 6 +++++- .../com/browserbase/api/errors/InternalServerException.kt | 7 ++++++- .../kotlin/com/browserbase/api/errors/NotFoundException.kt | 6 +++++- .../browserbase/api/errors/PermissionDeniedException.kt | 6 +++++- .../com/browserbase/api/errors/RateLimitException.kt | 6 +++++- .../main/kotlin/com/browserbase/api/errors/SseException.kt | 7 ++++++- .../com/browserbase/api/errors/UnauthorizedException.kt | 6 +++++- .../api/errors/UnexpectedStatusCodeException.kt | 7 ++++++- .../browserbase/api/errors/UnprocessableEntityException.kt | 6 +++++- 9 files changed, 48 insertions(+), 9 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt index c56095d..3f21e7c 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/BadRequestException.kt @@ -5,12 +5,16 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull class BadRequestException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("400: $body", cause) { + StagehandServiceException( + "400: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = 400 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt index c2b0d58..1f782c0 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/InternalServerException.kt @@ -5,6 +5,7 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,7 +15,11 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : StagehandServiceException("$statusCode: $body", cause) { +) : + StagehandServiceException( + "$statusCode: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = statusCode diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt index b8dcbd2..b3e3f6f 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/NotFoundException.kt @@ -5,12 +5,16 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull class NotFoundException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("404: $body", cause) { + StagehandServiceException( + "404: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = 404 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt index 4c37a8a..79c4ddb 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/PermissionDeniedException.kt @@ -5,12 +5,16 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull class PermissionDeniedException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("403: $body", cause) { + StagehandServiceException( + "403: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = 403 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt index b72ef4f..34c3d23 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/RateLimitException.kt @@ -5,12 +5,16 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull class RateLimitException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("429: $body", cause) { + StagehandServiceException( + "429: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = 429 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt index 0dfdd2f..8c902f5 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/SseException.kt @@ -5,6 +5,7 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,7 +15,11 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : StagehandServiceException("$statusCode: $body", cause) { +) : + StagehandServiceException( + "$statusCode: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = statusCode diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt index 23ed90e..37597f5 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnauthorizedException.kt @@ -5,12 +5,16 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull class UnauthorizedException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("401: $body", cause) { + StagehandServiceException( + "401: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = 401 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt index c375faa..e013e77 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnexpectedStatusCodeException.kt @@ -5,6 +5,7 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull @@ -14,7 +15,11 @@ private constructor( private val headers: Headers, private val body: JsonValue, cause: Throwable?, -) : StagehandServiceException("$statusCode: $body", cause) { +) : + StagehandServiceException( + "$statusCode: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = statusCode diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt index a162609..233efac 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/errors/UnprocessableEntityException.kt @@ -5,12 +5,16 @@ package com.browserbase.api.errors import com.browserbase.api.core.JsonValue import com.browserbase.api.core.checkRequired import com.browserbase.api.core.http.Headers +import com.browserbase.api.core.jsonMapper import java.util.Optional import kotlin.jvm.optionals.getOrNull class UnprocessableEntityException private constructor(private val headers: Headers, private val body: JsonValue, cause: Throwable?) : - StagehandServiceException("422: $body", cause) { + StagehandServiceException( + "422: ${if (body.isMissing()) "Unknown" else jsonMapper().writeValueAsString(body)}", + cause, + ) { override fun statusCode(): Int = 422 From e317cdcfb727cb9fb8cd183796a5f6a353081d8b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 02:09:27 +0000 Subject: [PATCH 151/164] docs: remove bad semicolon --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e51da24..4917f46 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ client.async().sessions().actStreaming(params) .subscribe(chunk -> { System.out.println(chunk); }) - .onCompleteFuture(); + .onCompleteFuture() .whenComplete((unused, error) -> { if (error != null) { System.out.println("Something went wrong!"); From ed852cf5d0ca6bba304ffca6c3456237d5c8686e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 02:10:14 +0000 Subject: [PATCH 152/164] chore: remove duplicated dokka setup --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7d91da7..effad83 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,6 @@ subprojects { group = "Verification" description = "Verifies all source files are formatted." } - apply(plugin = "org.jetbrains.dokka") } subprojects { From 40091cf2ed915fd45e08bb621bdf350909c4789d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 02:12:36 +0000 Subject: [PATCH 153/164] perf(client): create one json mapper --- .../src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt index 5200d47..65b7e72 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ObjectMappers.kt @@ -29,7 +29,9 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoField -fun jsonMapper(): JsonMapper = +fun jsonMapper(): JsonMapper = JSON_MAPPER + +private val JSON_MAPPER: JsonMapper = JsonMapper.builder() .addModule(kotlinModule()) .addModule(Jdk8Module()) From 16fe5366ddbe3e8b92537e89326a2139ed89eef6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 02:05:26 +0000 Subject: [PATCH 154/164] feat(client): support proxy authentication --- README.md | 15 ++ .../api/client/okhttp/OkHttpClient.kt | 234 +++++++++++------- .../client/okhttp/StagehandOkHttpClient.kt | 17 ++ .../okhttp/StagehandOkHttpClientAsync.kt | 17 ++ .../api/core/http/ProxyAuthenticator.kt | 59 +++++ 5 files changed, 257 insertions(+), 85 deletions(-) create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/ProxyAuthenticator.kt diff --git a/README.md b/README.md index 4917f46..77912cd 100644 --- a/README.md +++ b/README.md @@ -450,6 +450,21 @@ StagehandClient client = StagehandOkHttpClient.builder() .build(); ``` +If the proxy responds with `407 Proxy Authentication Required`, supply credentials by also configuring `proxyAuthenticator`: + +```java +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; +import com.browserbase.api.core.http.ProxyAuthenticator; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .proxy(...) + // Or a custom implementation of `ProxyAuthenticator`. + .proxyAuthenticator(ProxyAuthenticator.basic("username", "password")) + .build(); +``` + ### Connection pooling To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods: diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index 688abb6..ddad15d 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -8,9 +8,11 @@ import com.browserbase.api.core.http.HttpMethod import com.browserbase.api.core.http.HttpRequest import com.browserbase.api.core.http.HttpRequestBody import com.browserbase.api.core.http.HttpResponse +import com.browserbase.api.core.http.ProxyAuthenticator import com.browserbase.api.errors.StagehandIoException import java.io.IOException import java.io.InputStream +import java.io.OutputStream import java.net.Proxy import java.time.Duration import java.util.concurrent.CancellationException @@ -20,10 +22,12 @@ import java.util.concurrent.TimeUnit import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLSocketFactory import javax.net.ssl.X509TrustManager +import kotlin.jvm.optionals.getOrNull import okhttp3.Call import okhttp3.Callback import okhttp3.ConnectionPool import okhttp3.Dispatcher +import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType @@ -33,6 +37,8 @@ import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import okhttp3.logging.HttpLoggingInterceptor import okio.BufferedSink +import okio.buffer +import okio.sink class OkHttpClient internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClient) : HttpClient { @@ -41,7 +47,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie val call = newCall(request, requestOptions) return try { - call.execute().toResponse() + call.execute().toHttpResponse() } catch (e: IOException) { throw StagehandIoException("Request failed", e) } finally { @@ -59,7 +65,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie call.enqueue( object : Callback { override fun onResponse(call: Call, response: Response) { - future.complete(response.toResponse()) + future.complete(response.toHttpResponse()) } override fun onFailure(call: Call, e: IOException) { @@ -115,89 +121,6 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie return client.newCall(request.toRequest(client)) } - private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient): Request { - var body: RequestBody? = body?.toRequestBody() - if (body == null && requiresBody(method)) { - body = "".toRequestBody() - } - - val builder = Request.Builder().url(toUrl()).method(method.name, body) - headers.names().forEach { name -> - headers.values(name).forEach { builder.addHeader(name, it) } - } - - if ( - !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0 - ) { - builder.addHeader( - "X-Stainless-Read-Timeout", - Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(), - ) - } - if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) { - builder.addHeader( - "X-Stainless-Timeout", - Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(), - ) - } - - return builder.build() - } - - /** `OkHttpClient` always requires a request body for some methods. */ - private fun requiresBody(method: HttpMethod): Boolean = - when (method) { - HttpMethod.POST, - HttpMethod.PUT, - HttpMethod.PATCH -> true - else -> false - } - - private fun HttpRequest.toUrl(): String { - val builder = baseUrl.toHttpUrl().newBuilder() - pathSegments.forEach(builder::addPathSegment) - queryParams.keys().forEach { key -> - queryParams.values(key).forEach { builder.addQueryParameter(key, it) } - } - - return builder.toString() - } - - private fun HttpRequestBody.toRequestBody(): RequestBody { - val mediaType = contentType()?.toMediaType() - val length = contentLength() - - return object : RequestBody() { - override fun contentType(): MediaType? = mediaType - - override fun contentLength(): Long = length - - override fun isOneShot(): Boolean = !repeatable() - - override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream()) - } - } - - private fun Response.toResponse(): HttpResponse { - val headers = headers.toHeaders() - - return object : HttpResponse { - override fun statusCode(): Int = code - - override fun headers(): Headers = headers - - override fun body(): InputStream = body!!.byteStream() - - override fun close() = body!!.close() - } - } - - private fun okhttp3.Headers.toHeaders(): Headers { - val headersBuilder = Headers.builder() - forEach { (name, value) -> headersBuilder.put(name, value) } - return headersBuilder.build() - } - companion object { @JvmStatic fun builder() = Builder() } @@ -206,6 +129,7 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie private var timeout: Timeout = Timeout.default() private var proxy: Proxy? = null + private var proxyAuthenticator: ProxyAuthenticator? = null private var maxIdleConnections: Int? = null private var keepAliveDuration: Duration? = null private var dispatcherExecutorService: ExecutorService? = null @@ -219,6 +143,10 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie fun proxy(proxy: Proxy?) = apply { this.proxy = proxy } + fun proxyAuthenticator(proxyAuthenticator: ProxyAuthenticator?) = apply { + this.proxyAuthenticator = proxyAuthenticator + } + /** * Sets the maximum number of idle connections kept by the underlying [ConnectionPool]. * @@ -268,6 +196,19 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie .callTimeout(timeout.request()) .proxy(proxy) .apply { + proxyAuthenticator?.let { auth -> + proxyAuthenticator { route, response -> + auth + .authenticate( + route?.proxy ?: Proxy.NO_PROXY, + response.request.toHttpRequest(), + response.toHttpResponse(), + ) + .getOrNull() + ?.toRequest(client = null) + } + } + dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) } val maxIdleConnections = maxIdleConnections @@ -307,3 +248,126 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie ) } } + +private fun HttpRequest.toRequest(client: okhttp3.OkHttpClient?): Request { + var body: RequestBody? = body?.toRequestBody() + if (body == null && requiresBody(method)) { + body = "".toRequestBody() + } + + val builder = Request.Builder().url(toUrl()).method(method.name, body) + headers.names().forEach { name -> headers.values(name).forEach { builder.addHeader(name, it) } } + + if (client != null) { + if ( + !headers.names().contains("X-Stainless-Read-Timeout") && client.readTimeoutMillis != 0 + ) { + builder.addHeader( + "X-Stainless-Read-Timeout", + Duration.ofMillis(client.readTimeoutMillis.toLong()).seconds.toString(), + ) + } + if (!headers.names().contains("X-Stainless-Timeout") && client.callTimeoutMillis != 0) { + builder.addHeader( + "X-Stainless-Timeout", + Duration.ofMillis(client.callTimeoutMillis.toLong()).seconds.toString(), + ) + } + } + + return builder.build() +} + +/** `OkHttpClient` always requires a request body for some methods. */ +private fun requiresBody(method: HttpMethod): Boolean = + when (method) { + HttpMethod.POST, + HttpMethod.PUT, + HttpMethod.PATCH -> true + else -> false + } + +private fun HttpRequest.toUrl(): String { + val builder = baseUrl.toHttpUrl().newBuilder() + pathSegments.forEach(builder::addPathSegment) + queryParams.keys().forEach { key -> + queryParams.values(key).forEach { builder.addQueryParameter(key, it) } + } + + return builder.toString() +} + +private fun HttpRequestBody.toRequestBody(): RequestBody { + val mediaType = contentType()?.toMediaType() + val length = contentLength() + + return object : RequestBody() { + override fun contentType(): MediaType? = mediaType + + override fun contentLength(): Long = length + + override fun isOneShot(): Boolean = !repeatable() + + override fun writeTo(sink: BufferedSink) = writeTo(sink.outputStream()) + } +} + +private fun Request.toHttpRequest(): HttpRequest { + val builder = HttpRequest.builder().method(HttpMethod.valueOf(method)).baseUrl(url.toBaseUrl()) + url.pathSegments.forEach(builder::addPathSegment) + url.queryParameterNames.forEach { name -> + url.queryParameterValues(name).filterNotNull().forEach { builder.putQueryParam(name, it) } + } + headers.forEach { (name, value) -> builder.putHeader(name, value) } + body?.let { builder.body(it.toHttpRequestBody()) } + return builder.build() +} + +private fun HttpUrl.toBaseUrl(): String = buildString { + append(scheme).append("://").append(host) + if (port != HttpUrl.defaultPort(scheme)) { + append(":").append(port) + } +} + +private fun RequestBody.toHttpRequestBody(): HttpRequestBody { + val mediaType = contentType()?.toString() + val length = contentLength() + val isOneShot = isOneShot() + val source = this + return object : HttpRequestBody { + override fun contentType(): String? = mediaType + + override fun contentLength(): Long = length + + override fun repeatable(): Boolean = !isOneShot + + override fun writeTo(outputStream: OutputStream) { + val sink = outputStream.sink().buffer() + source.writeTo(sink) + sink.flush() + } + + override fun close() {} + } +} + +private fun Response.toHttpResponse(): HttpResponse { + val headers = headers.toHeaders() + + return object : HttpResponse { + override fun statusCode(): Int = code + + override fun headers(): Headers = headers + + override fun body(): InputStream = body!!.byteStream() + + override fun close() = body!!.close() + } +} + +private fun okhttp3.Headers.toHeaders(): Headers { + val headersBuilder = Headers.builder() + forEach { (name, value) -> headersBuilder.put(name, value) } + return headersBuilder.build() +} diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index b5e471d..e431572 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -10,6 +10,7 @@ import com.browserbase.api.core.Timeout import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.ProxyAuthenticator import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.databind.json.JsonMapper @@ -49,6 +50,7 @@ class StagehandOkHttpClient private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null + private var proxyAuthenticator: ProxyAuthenticator? = null private var maxIdleConnections: Int? = null private var keepAliveDuration: Duration? = null private var sslSocketFactory: SSLSocketFactory? = null @@ -79,6 +81,20 @@ class StagehandOkHttpClient private constructor() { /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + /** + * Provides credentials when an HTTP proxy responds with `407 Proxy Authentication + * Required`. + */ + fun proxyAuthenticator(proxyAuthenticator: ProxyAuthenticator?) = apply { + this.proxyAuthenticator = proxyAuthenticator + } + + /** + * Alias for calling [Builder.proxyAuthenticator] with `proxyAuthenticator.orElse(null)`. + */ + fun proxyAuthenticator(proxyAuthenticator: Optional) = + proxyAuthenticator(proxyAuthenticator.getOrNull()) + /** * The maximum number of idle connections kept by the underlying OkHttp connection pool. * @@ -386,6 +402,7 @@ class StagehandOkHttpClient private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .proxyAuthenticator(proxyAuthenticator) .maxIdleConnections(maxIdleConnections) .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 924c40f..1dba92a 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -10,6 +10,7 @@ import com.browserbase.api.core.Timeout import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.ProxyAuthenticator import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.jsonMapper import com.fasterxml.jackson.databind.json.JsonMapper @@ -49,6 +50,7 @@ class StagehandOkHttpClientAsync private constructor() { private var clientOptions: ClientOptions.Builder = ClientOptions.builder() private var dispatcherExecutorService: ExecutorService? = null private var proxy: Proxy? = null + private var proxyAuthenticator: ProxyAuthenticator? = null private var maxIdleConnections: Int? = null private var keepAliveDuration: Duration? = null private var sslSocketFactory: SSLSocketFactory? = null @@ -79,6 +81,20 @@ class StagehandOkHttpClientAsync private constructor() { /** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */ fun proxy(proxy: Optional) = proxy(proxy.getOrNull()) + /** + * Provides credentials when an HTTP proxy responds with `407 Proxy Authentication + * Required`. + */ + fun proxyAuthenticator(proxyAuthenticator: ProxyAuthenticator?) = apply { + this.proxyAuthenticator = proxyAuthenticator + } + + /** + * Alias for calling [Builder.proxyAuthenticator] with `proxyAuthenticator.orElse(null)`. + */ + fun proxyAuthenticator(proxyAuthenticator: Optional) = + proxyAuthenticator(proxyAuthenticator.getOrNull()) + /** * The maximum number of idle connections kept by the underlying OkHttp connection pool. * @@ -386,6 +402,7 @@ class StagehandOkHttpClientAsync private constructor() { OkHttpClient.builder() .timeout(clientOptions.timeout()) .proxy(proxy) + .proxyAuthenticator(proxyAuthenticator) .maxIdleConnections(maxIdleConnections) .keepAliveDuration(keepAliveDuration) .dispatcherExecutorService(dispatcherExecutorService) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/ProxyAuthenticator.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/ProxyAuthenticator.kt new file mode 100644 index 0000000..75e750b --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/ProxyAuthenticator.kt @@ -0,0 +1,59 @@ +package com.browserbase.api.core.http + +import java.net.Proxy +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets +import java.util.Base64 +import java.util.Optional + +/** + * Provides credentials when an HTTP proxy responds with `407 Proxy Authentication Required`. + * + * Implementations inspect the 407 [response] (typically its `Proxy-Authenticate` header) and return + * the request to retry with a `Proxy-Authorization` header set, or [Optional.empty] to abandon + * authentication and surface the 407 to the caller. + * + * Implementations must be thread-safe; they may be invoked concurrently from multiple HTTP calls. + */ +fun interface ProxyAuthenticator { + + /** + * @param proxy the proxy that produced the challenge, or [Proxy.NO_PROXY] if the route is not + * yet established + * @param request the request that produced [response] + * @param response the 407 challenge response + * @return the retry request to send (typically [request] with a `Proxy-Authorization` header + * added), or [Optional.empty] to abandon authentication + */ + fun authenticate( + proxy: Proxy, + request: HttpRequest, + response: HttpResponse, + ): Optional + + companion object { + + /** + * A [ProxyAuthenticator] that uses RFC 7617 Basic authentication with the ISO-8859-1 + * charset. + */ + @JvmStatic + fun basic(username: String, password: String): ProxyAuthenticator = + basic(username, password, StandardCharsets.ISO_8859_1) + + /** + * A [ProxyAuthenticator] that uses RFC 7617 Basic authentication with the given [charset]. + */ + @JvmStatic + fun basic(username: String, password: String, charset: Charset): ProxyAuthenticator { + val token = + Base64.getEncoder().encodeToString("$username:$password".toByteArray(charset)) + val headerValue = "Basic $token" + return ProxyAuthenticator { _, request, _ -> + Optional.of( + request.toBuilder().putHeader("Proxy-Authorization", headerValue).build() + ) + } + } + } +} From aa7cfa5dc1b36a2d76b3563c673134cbbcf1ed4d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 17:06:19 +0000 Subject: [PATCH 155/164] feat: [feat]: add `ignoreSelectors` to `extract()` --- .stats.yml | 4 +- .../models/sessions/SessionExtractParams.kt | 72 +++++++++++++++++-- .../sessions/SessionExtractParamsTest.kt | 4 ++ .../services/async/SessionServiceAsyncTest.kt | 2 + .../services/blocking/SessionServiceTest.kt | 2 + 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index b17eb0a..128128c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-dbbff1a35360850898f7d60588e257faeac145a73cfcae634cfeb1b70109b6af.yml -openapi_spec_hash: 28c4b734a5309067c39bb4c4b709b9ab +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-7182c741edd5e22cda9bd855d31ca7e60a97a409222bb887edf87b9ce15dd493.yml +openapi_spec_hash: 174581867a9191c491b22855b64c4f19 config_hash: a962ae71493deb11a1c903256fb25386 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt index 2e7574c..5c5fe92 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExtractParams.kt @@ -11,6 +11,7 @@ import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkKnown import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams @@ -632,6 +633,7 @@ private constructor( class Options @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val ignoreSelectors: JsonField>, private val model: JsonField, private val selector: JsonField, private val timeout: JsonField, @@ -640,12 +642,24 @@ private constructor( @JsonCreator private constructor( + @JsonProperty("ignoreSelectors") + @ExcludeMissing + ignoreSelectors: JsonField> = JsonMissing.of(), @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("selector") @ExcludeMissing selector: JsonField = JsonMissing.of(), @JsonProperty("timeout") @ExcludeMissing timeout: JsonField = JsonMissing.of(), - ) : this(model, selector, timeout, mutableMapOf()) + ) : this(ignoreSelectors, model, selector, timeout, mutableMapOf()) + + /** + * Selectors for elements and subtrees that should be excluded from extraction + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun ignoreSelectors(): Optional> = + ignoreSelectors.getOptional("ignoreSelectors") /** * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') @@ -671,6 +685,16 @@ private constructor( */ fun timeout(): Optional = timeout.getOptional("timeout") + /** + * Returns the raw JSON value of [ignoreSelectors]. + * + * Unlike [ignoreSelectors], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("ignoreSelectors") + @ExcludeMissing + fun _ignoreSelectors(): JsonField> = ignoreSelectors + /** * Returns the raw JSON value of [model]. * @@ -713,6 +737,7 @@ private constructor( /** A builder for [Options]. */ class Builder internal constructor() { + private var ignoreSelectors: JsonField>? = null private var model: JsonField = JsonMissing.of() private var selector: JsonField = JsonMissing.of() private var timeout: JsonField = JsonMissing.of() @@ -720,12 +745,40 @@ private constructor( @JvmSynthetic internal fun from(options: Options) = apply { + ignoreSelectors = options.ignoreSelectors.map { it.toMutableList() } model = options.model selector = options.selector timeout = options.timeout additionalProperties = options.additionalProperties.toMutableMap() } + /** Selectors for elements and subtrees that should be excluded from extraction */ + fun ignoreSelectors(ignoreSelectors: List) = + ignoreSelectors(JsonField.of(ignoreSelectors)) + + /** + * Sets [Builder.ignoreSelectors] to an arbitrary JSON value. + * + * You should usually call [Builder.ignoreSelectors] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun ignoreSelectors(ignoreSelectors: JsonField>) = apply { + this.ignoreSelectors = ignoreSelectors.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [ignoreSelectors]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addIgnoreSelector(ignoreSelector: String) = apply { + ignoreSelectors = + (ignoreSelectors ?: JsonField.of(mutableListOf())).also { + checkKnown("ignoreSelectors", it).add(ignoreSelector) + } + } + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ fun model(model: Model) = model(JsonField.of(model)) @@ -793,7 +846,13 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): Options = - Options(model, selector, timeout, additionalProperties.toMutableMap()) + Options( + (ignoreSelectors ?: JsonMissing.of()).map { it.toImmutable() }, + model, + selector, + timeout, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -812,6 +871,7 @@ private constructor( return@apply } + ignoreSelectors() model().ifPresent { it.validate() } selector() timeout() @@ -834,7 +894,8 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (model.asKnown().getOrNull()?.validity() ?: 0) + + (ignoreSelectors.asKnown().getOrNull()?.size ?: 0) + + (model.asKnown().getOrNull()?.validity() ?: 0) + (if (selector.asKnown().isPresent) 1 else 0) + (if (timeout.asKnown().isPresent) 1 else 0) @@ -1056,6 +1117,7 @@ private constructor( } return other is Options && + ignoreSelectors == other.ignoreSelectors && model == other.model && selector == other.selector && timeout == other.timeout && @@ -1063,13 +1125,13 @@ private constructor( } private val hashCode: Int by lazy { - Objects.hash(model, selector, timeout, additionalProperties) + Objects.hash(ignoreSelectors, model, selector, timeout, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Options{model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" + "Options{ignoreSelectors=$ignoreSelectors, model=$model, selector=$selector, timeout=$timeout, additionalProperties=$additionalProperties}" } /** JSON Schema defining the structure of data to extract */ diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt index d84a3f9..30d7652 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExtractParamsTest.kt @@ -18,6 +18,7 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -63,6 +64,7 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -112,6 +114,7 @@ internal class SessionExtractParamsTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -144,6 +147,7 @@ internal class SessionExtractParamsTest { assertThat(body.options()) .contains( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index a21bd07..1c786f9 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -317,6 +317,7 @@ internal class SessionServiceAsyncTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -366,6 +367,7 @@ internal class SessionServiceAsyncTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 7923bb5..f8ffea6 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -314,6 +314,7 @@ internal class SessionServiceTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -362,6 +363,7 @@ internal class SessionServiceTest { .instruction("Extract all product names and prices from the page") .options( SessionExtractParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") From f6729f2932c56433e3ba5c9f6460ce81fa34b449 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 17:12:03 +0000 Subject: [PATCH 156/164] feat: [STG-1808] Deprecate Browserbase project ID --- .stats.yml | 6 ++-- README.md | 2 +- .../client/okhttp/StagehandOkHttpClient.kt | 14 +++++++-- .../okhttp/StagehandOkHttpClientAsync.kt | 14 +++++++-- .../com/browserbase/api/core/ClientOptions.kt | 29 +++++++++++++------ .../api/models/sessions/SessionStartParams.kt | 15 +++++++++- 6 files changed, 62 insertions(+), 18 deletions(-) diff --git a/.stats.yml b/.stats.yml index 128128c..d79c632 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-7182c741edd5e22cda9bd855d31ca7e60a97a409222bb887edf87b9ce15dd493.yml -openapi_spec_hash: 174581867a9191c491b22855b64c4f19 -config_hash: a962ae71493deb11a1c903256fb25386 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-f10429ab9f004c9a7f9f362d7fa82915e0dc04b1ba08a7bc9fd442ed5854cc77.yml +openapi_spec_hash: 818f2e6e7eb5eb6f21f346b0b9828dce +config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 diff --git a/README.md b/README.md index 77912cd..f9750ed 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ See this table for the available options: | Setter | System property | Environment variable | Required | Default value | | ---------------------- | -------------------------------- | ------------------------ | -------- | ----------------------------------------- | | `browserbaseApiKey` | `stagehand.browserbaseApiKey` | `BROWSERBASE_API_KEY` | true | - | -| `browserbaseProjectId` | `stagehand.browserbaseProjectId` | `BROWSERBASE_PROJECT_ID` | true | - | +| `browserbaseProjectId` | `stagehand.browserbaseProjectId` | `BROWSERBASE_PROJECT_ID` | false | - | | `modelApiKey` | `stagehand.modelApiKey` | `MODEL_API_KEY` | true | - | | `baseUrl` | `stagehand.baseUrl` | `STAGEHAND_BASE_URL` | true | `"https://api.stagehand.browserbase.com"` | diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index e431572..972d3e3 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -295,11 +295,21 @@ class StagehandOkHttpClient private constructor() { clientOptions.browserbaseApiKey(browserbaseApiKey) } - /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ - fun browserbaseProjectId(browserbaseProjectId: String) = apply { + /** + * Deprecated. Browserbase API keys are now project-scoped, so this value is no longer + * required. + */ + fun browserbaseProjectId(browserbaseProjectId: String?) = apply { clientOptions.browserbaseProjectId(browserbaseProjectId) } + /** + * Alias for calling [Builder.browserbaseProjectId] with + * `browserbaseProjectId.orElse(null)`. + */ + fun browserbaseProjectId(browserbaseProjectId: Optional) = + browserbaseProjectId(browserbaseProjectId.getOrNull()) + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ fun modelApiKey(modelApiKey: String) = apply { clientOptions.modelApiKey(modelApiKey) } diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 1dba92a..321443a 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -295,11 +295,21 @@ class StagehandOkHttpClientAsync private constructor() { clientOptions.browserbaseApiKey(browserbaseApiKey) } - /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ - fun browserbaseProjectId(browserbaseProjectId: String) = apply { + /** + * Deprecated. Browserbase API keys are now project-scoped, so this value is no longer + * required. + */ + fun browserbaseProjectId(browserbaseProjectId: String?) = apply { clientOptions.browserbaseProjectId(browserbaseProjectId) } + /** + * Alias for calling [Builder.browserbaseProjectId] with + * `browserbaseProjectId.orElse(null)`. + */ + fun browserbaseProjectId(browserbaseProjectId: Optional) = + browserbaseProjectId(browserbaseProjectId.getOrNull()) + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ fun modelApiKey(modelApiKey: String) = apply { clientOptions.modelApiKey(modelApiKey) } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 6e33f5d..860a728 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -112,8 +112,7 @@ private constructor( @get:JvmName("maxRetries") val maxRetries: Int, /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ @get:JvmName("browserbaseApiKey") val browserbaseApiKey: String, - /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ - @get:JvmName("browserbaseProjectId") val browserbaseProjectId: String, + private val browserbaseProjectId: String?, /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ @get:JvmName("modelApiKey") val modelApiKey: String, ) { @@ -131,6 +130,11 @@ private constructor( */ fun baseUrl(): String = baseUrl ?: PRODUCTION_URL + /** + * Deprecated. Browserbase API keys are now project-scoped, so this value is no longer required. + */ + fun browserbaseProjectId(): Optional = Optional.ofNullable(browserbaseProjectId) + fun toBuilder() = Builder().from(this) companion object { @@ -144,7 +148,6 @@ private constructor( * ```java * .httpClient() * .browserbaseApiKey() - * .browserbaseProjectId() * .modelApiKey() * ``` */ @@ -322,11 +325,21 @@ private constructor( this.browserbaseApiKey = browserbaseApiKey } - /** Your [Browserbase Project ID](https://www.browserbase.com/settings) */ - fun browserbaseProjectId(browserbaseProjectId: String) = apply { + /** + * Deprecated. Browserbase API keys are now project-scoped, so this value is no longer + * required. + */ + fun browserbaseProjectId(browserbaseProjectId: String?) = apply { this.browserbaseProjectId = browserbaseProjectId } + /** + * Alias for calling [Builder.browserbaseProjectId] with + * `browserbaseProjectId.orElse(null)`. + */ + fun browserbaseProjectId(browserbaseProjectId: Optional) = + browserbaseProjectId(browserbaseProjectId.getOrNull()) + /** Your LLM provider API key (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) */ fun modelApiKey(modelApiKey: String) = apply { this.modelApiKey = modelApiKey } @@ -420,7 +433,7 @@ private constructor( * |Setter |System property |Environment variable |Required|Default value | * |----------------------|--------------------------------|------------------------|--------|-----------------------------------------| * |`browserbaseApiKey` |`stagehand.browserbaseApiKey` |`BROWSERBASE_API_KEY` |true |- | - * |`browserbaseProjectId`|`stagehand.browserbaseProjectId`|`BROWSERBASE_PROJECT_ID`|true |- | + * |`browserbaseProjectId`|`stagehand.browserbaseProjectId`|`BROWSERBASE_PROJECT_ID`|false |- | * |`modelApiKey` |`stagehand.modelApiKey` |`MODEL_API_KEY` |true |- | * |`baseUrl` |`stagehand.baseUrl` |`STAGEHAND_BASE_URL` |true |`"https://api.stagehand.browserbase.com"`| * @@ -458,7 +471,6 @@ private constructor( * ```java * .httpClient() * .browserbaseApiKey() - * .browserbaseProjectId() * .modelApiKey() * ``` * @@ -486,7 +498,6 @@ private constructor( ) val sleeper = sleeper ?: PhantomReachableSleeper(DefaultSleeper()) val browserbaseApiKey = checkRequired("browserbaseApiKey", browserbaseApiKey) - val browserbaseProjectId = checkRequired("browserbaseProjectId", browserbaseProjectId) val modelApiKey = checkRequired("modelApiKey", modelApiKey) val headers = Headers.builder() @@ -507,7 +518,7 @@ private constructor( headers.replace("x-bb-api-key", it) } } - browserbaseProjectId.let { + browserbaseProjectId?.let { if (!it.isEmpty()) { headers.replace("x-bb-project-id", it) } diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt index d940a91..7d6d521 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionStartParams.kt @@ -3392,9 +3392,13 @@ private constructor( fun keepAlive(): Optional = keepAlive.getOptional("keepAlive") /** + * Deprecated. Browserbase API keys are now project-scoped, so this field is no longer + * required. + * * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ + @Deprecated("deprecated") fun projectId(): Optional = projectId.getOptional("projectId") /** @@ -3452,7 +3456,10 @@ private constructor( * * Unlike [projectId], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("projectId") @ExcludeMissing fun _projectId(): JsonField = projectId + @Deprecated("deprecated") + @JsonProperty("projectId") + @ExcludeMissing + fun _projectId(): JsonField = projectId /** * Returns the raw JSON value of [proxies]. @@ -3572,6 +3579,11 @@ private constructor( */ fun keepAlive(keepAlive: JsonField) = apply { this.keepAlive = keepAlive } + /** + * Deprecated. Browserbase API keys are now project-scoped, so this field is no longer + * required. + */ + @Deprecated("deprecated") fun projectId(projectId: String) = projectId(JsonField.of(projectId)) /** @@ -3581,6 +3593,7 @@ private constructor( * This method is primarily for setting the field to an undocumented or not yet * supported value. */ + @Deprecated("deprecated") fun projectId(projectId: JsonField) = apply { this.projectId = projectId } fun proxies(proxies: Proxies) = proxies(JsonField.of(proxies)) From aeaf15cb38795ba409ac0e5f31f833c7589863fd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 18:52:34 +0000 Subject: [PATCH 157/164] feat: remove experimental requirement on agent variables (#2079) --- .stats.yml | 4 +- .../models/sessions/SessionExecuteParams.kt | 168 +++++++++++++++++- .../sessions/SessionExecuteParamsTest.kt | 20 +++ .../services/async/SessionServiceAsyncTest.kt | 10 ++ .../services/blocking/SessionServiceTest.kt | 10 ++ 5 files changed, 207 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index d79c632..391cde3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-f10429ab9f004c9a7f9f362d7fa82915e0dc04b1ba08a7bc9fd442ed5854cc77.yml -openapi_spec_hash: 818f2e6e7eb5eb6f21f346b0b9828dce +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-6f6bfb81d092f30a5e2005328c97d61b9ea36132bb19e9e79e55294b9534ce20.yml +openapi_spec_hash: f3fc1e3688a38dc2c28f7178f7d534e5 config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt index c850bce..d124ba0 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionExecuteParams.kt @@ -15,6 +15,7 @@ import com.browserbase.api.core.checkRequired import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams +import com.browserbase.api.core.toImmutable import com.browserbase.api.errors.StagehandInvalidDataException import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -1806,6 +1807,7 @@ private constructor( private val maxSteps: JsonField, private val toolTimeout: JsonField, private val useSearch: JsonField, + private val variables: JsonField, private val additionalProperties: MutableMap, ) { @@ -1826,7 +1828,18 @@ private constructor( @JsonProperty("useSearch") @ExcludeMissing useSearch: JsonField = JsonMissing.of(), - ) : this(instruction, highlightCursor, maxSteps, toolTimeout, useSearch, mutableMapOf()) + @JsonProperty("variables") + @ExcludeMissing + variables: JsonField = JsonMissing.of(), + ) : this( + instruction, + highlightCursor, + maxSteps, + toolTimeout, + useSearch, + variables, + mutableMapOf(), + ) /** * Natural language instruction for the agent @@ -1868,6 +1881,14 @@ private constructor( */ fun useSearch(): Optional = useSearch.getOptional("useSearch") + /** + * Variables available to the agent via %variableName% syntax in supported tools + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun variables(): Optional = variables.getOptional("variables") + /** * Returns the raw JSON value of [instruction]. * @@ -1910,6 +1931,15 @@ private constructor( */ @JsonProperty("useSearch") @ExcludeMissing fun _useSearch(): JsonField = useSearch + /** + * Returns the raw JSON value of [variables]. + * + * Unlike [variables], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("variables") + @ExcludeMissing + fun _variables(): JsonField = variables + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1943,6 +1973,7 @@ private constructor( private var maxSteps: JsonField = JsonMissing.of() private var toolTimeout: JsonField = JsonMissing.of() private var useSearch: JsonField = JsonMissing.of() + private var variables: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -1952,6 +1983,7 @@ private constructor( maxSteps = executeOptions.maxSteps toolTimeout = executeOptions.toolTimeout useSearch = executeOptions.useSearch + variables = executeOptions.variables additionalProperties = executeOptions.additionalProperties.toMutableMap() } @@ -2022,6 +2054,18 @@ private constructor( */ fun useSearch(useSearch: JsonField) = apply { this.useSearch = useSearch } + /** Variables available to the agent via %variableName% syntax in supported tools */ + fun variables(variables: Variables) = variables(JsonField.of(variables)) + + /** + * Sets [Builder.variables] to an arbitrary JSON value. + * + * You should usually call [Builder.variables] with a well-typed [Variables] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun variables(variables: JsonField) = apply { this.variables = variables } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -2060,6 +2104,7 @@ private constructor( maxSteps, toolTimeout, useSearch, + variables, additionalProperties.toMutableMap(), ) } @@ -2085,6 +2130,7 @@ private constructor( maxSteps() toolTimeout() useSearch() + variables().ifPresent { it.validate() } validated = true } @@ -2108,7 +2154,121 @@ private constructor( (if (highlightCursor.asKnown().isPresent) 1 else 0) + (if (maxSteps.asKnown().isPresent) 1 else 0) + (if (toolTimeout.asKnown().isPresent) 1 else 0) + - (if (useSearch.asKnown().isPresent) 1 else 0) + (if (useSearch.asKnown().isPresent) 1 else 0) + + (variables.asKnown().getOrNull()?.validity() ?: 0) + + /** Variables available to the agent via %variableName% syntax in supported tools */ + class Variables + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Variables]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Variables]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(variables: Variables) = apply { + additionalProperties = variables.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Variables]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Variables = Variables(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws StagehandInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): Variables = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: StagehandInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Variables && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Variables{additionalProperties=$additionalProperties}" + } override fun equals(other: Any?): Boolean { if (this === other) { @@ -2121,6 +2281,7 @@ private constructor( maxSteps == other.maxSteps && toolTimeout == other.toolTimeout && useSearch == other.useSearch && + variables == other.variables && additionalProperties == other.additionalProperties } @@ -2131,6 +2292,7 @@ private constructor( maxSteps, toolTimeout, useSearch, + variables, additionalProperties, ) } @@ -2138,7 +2300,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, toolTimeout=$toolTimeout, useSearch=$useSearch, additionalProperties=$additionalProperties}" + "ExecuteOptions{instruction=$instruction, highlightCursor=$highlightCursor, maxSteps=$maxSteps, toolTimeout=$toolTimeout, useSearch=$useSearch, variables=$variables, additionalProperties=$additionalProperties}" } /** Whether to stream the response via SSE */ diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt index f040cad..da74169 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionExecuteParamsTest.kt @@ -57,6 +57,11 @@ internal class SessionExecuteParamsTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") @@ -133,6 +138,11 @@ internal class SessionExecuteParamsTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") @@ -213,6 +223,11 @@ internal class SessionExecuteParamsTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") @@ -266,6 +281,11 @@ internal class SessionExecuteParamsTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) assertThat(body.frameId()).contains("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 1c786f9..8d708e4 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -215,6 +215,11 @@ internal class SessionServiceAsyncTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") @@ -285,6 +290,11 @@ internal class SessionServiceAsyncTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index f8ffea6..7ede1f2 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -213,6 +213,11 @@ internal class SessionServiceTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") @@ -282,6 +287,11 @@ internal class SessionServiceTest { .maxSteps(20.0) .toolTimeout(30000.0) .useSearch(true) + .variables( + SessionExecuteParams.ExecuteOptions.Variables.builder() + .putAdditionalProperty("foo", JsonValue.from("string")) + .build() + ) .build() ) .frameId("frameId") From d3cb3ad556f650d178bb332f1d54006d16456356 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 02:11:53 +0000 Subject: [PATCH 158/164] feat(client): improve logging Logging is now: 1. Streaming 4. Configurable in-memory 5. Generally more robust 6. Usable with any underlying http client --- README.md | 15 +- stagehand-java-client-okhttp/build.gradle.kts | 1 - .../api/client/okhttp/OkHttpClient.kt | 17 - .../client/okhttp/StagehandOkHttpClient.kt | 10 + .../okhttp/StagehandOkHttpClientAsync.kt | 10 + .../com/browserbase/api/core/ClientOptions.kt | 30 +- .../com/browserbase/api/core/LogLevel.kt | 33 + .../kotlin/com/browserbase/api/core/Utils.kt | 6 + .../api/core/http/LoggingHttpClient.kt | 628 +++++++++++ .../api/core/http/LoggingHttpClientTest.kt | 999 ++++++++++++++++++ 10 files changed, 1728 insertions(+), 21 deletions(-) create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/core/LogLevel.kt create mode 100644 stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt create mode 100644 stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt diff --git a/README.md b/README.md index f9750ed..ab5d48e 100644 --- a/README.md +++ b/README.md @@ -342,8 +342,6 @@ The SDK throws custom unchecked exception types: ## Logging -The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). - Enable logging by setting the `STAGEHAND_LOG` environment variable to `info`: ```sh @@ -356,6 +354,19 @@ Or to `debug` for more verbose logging: export STAGEHAND_LOG=debug ``` +Or configure the client manually using the `logLevel` method: + +```java +import com.browserbase.api.client.StagehandClient; +import com.browserbase.api.client.okhttp.StagehandOkHttpClient; +import com.browserbase.api.core.LogLevel; + +StagehandClient client = StagehandOkHttpClient.builder() + .fromEnv() + .logLevel(LogLevel.INFO) + .build(); +``` + ## ProGuard and R8 Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `stagehand-java-core` is published with a [configuration file](stagehand-java-core/src/main/resources/META-INF/proguard/stagehand-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). diff --git a/stagehand-java-client-okhttp/build.gradle.kts b/stagehand-java-client-okhttp/build.gradle.kts index 49e7e71..be765aa 100644 --- a/stagehand-java-client-okhttp/build.gradle.kts +++ b/stagehand-java-client-okhttp/build.gradle.kts @@ -7,7 +7,6 @@ dependencies { api(project(":stagehand-java-core")) implementation("com.squareup.okhttp3:okhttp:4.12.0") - implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") testImplementation(kotlin("test")) testImplementation("org.assertj:assertj-core:3.27.7") diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt index ddad15d..155ae2b 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/OkHttpClient.kt @@ -35,7 +35,6 @@ import okhttp3.Request import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response -import okhttp3.logging.HttpLoggingInterceptor import okio.BufferedSink import okio.buffer import okio.sink @@ -93,22 +92,6 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie private fun newCall(request: HttpRequest, requestOptions: RequestOptions): Call { val clientBuilder = okHttpClient.newBuilder() - val logLevel = - when (System.getenv("STAGEHAND_LOG")?.lowercase()) { - "info" -> HttpLoggingInterceptor.Level.BASIC - "debug" -> HttpLoggingInterceptor.Level.BODY - else -> null - } - if (logLevel != null) { - clientBuilder.addNetworkInterceptor( - HttpLoggingInterceptor().setLevel(logLevel).apply { - redactHeader("x-bb-api-key") - redactHeader("x-bb-project-id") - redactHeader("x-model-api-key") - } - ) - } - requestOptions.timeout?.let { clientBuilder .connectTimeout(it.connect()) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt index 972d3e3..36e0fe3 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClient.kt @@ -5,6 +5,7 @@ package com.browserbase.api.client.okhttp import com.browserbase.api.client.StagehandClient import com.browserbase.api.client.StagehandClientImpl import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.LogLevel import com.browserbase.api.core.Sleeper import com.browserbase.api.core.Timeout import com.browserbase.api.core.http.AsyncStreamResponse @@ -290,6 +291,15 @@ class StagehandOkHttpClient private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + /** + * The level at which to log request and response information. + * + * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv]. + * + * Defaults to [LogLevel.fromEnv]. + */ + fun logLevel(logLevel: LogLevel) = apply { clientOptions.logLevel(logLevel) } + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ fun browserbaseApiKey(browserbaseApiKey: String) = apply { clientOptions.browserbaseApiKey(browserbaseApiKey) diff --git a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt index 321443a..83bb57e 100644 --- a/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt +++ b/stagehand-java-client-okhttp/src/main/kotlin/com/browserbase/api/client/okhttp/StagehandOkHttpClientAsync.kt @@ -5,6 +5,7 @@ package com.browserbase.api.client.okhttp import com.browserbase.api.client.StagehandClientAsync import com.browserbase.api.client.StagehandClientAsyncImpl import com.browserbase.api.core.ClientOptions +import com.browserbase.api.core.LogLevel import com.browserbase.api.core.Sleeper import com.browserbase.api.core.Timeout import com.browserbase.api.core.http.AsyncStreamResponse @@ -290,6 +291,15 @@ class StagehandOkHttpClientAsync private constructor() { */ fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) } + /** + * The level at which to log request and response information. + * + * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv]. + * + * Defaults to [LogLevel.fromEnv]. + */ + fun logLevel(logLevel: LogLevel) = apply { clientOptions.logLevel(logLevel) } + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ fun browserbaseApiKey(browserbaseApiKey: String) = apply { clientOptions.browserbaseApiKey(browserbaseApiKey) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt index 860a728..12d3001 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/ClientOptions.kt @@ -5,6 +5,7 @@ package com.browserbase.api.core import com.browserbase.api.core.http.AsyncStreamResponse import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.HttpClient +import com.browserbase.api.core.http.LoggingHttpClient import com.browserbase.api.core.http.PhantomReachableClosingHttpClient import com.browserbase.api.core.http.QueryParams import com.browserbase.api.core.http.RetryingHttpClient @@ -110,6 +111,14 @@ private constructor( * Defaults to 2. */ @get:JvmName("maxRetries") val maxRetries: Int, + /** + * The level at which to log request and response information. + * + * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv]. + * + * Defaults to [LogLevel.fromEnv]. + */ + @get:JvmName("logLevel") val logLevel: LogLevel, /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ @get:JvmName("browserbaseApiKey") val browserbaseApiKey: String, private val browserbaseProjectId: String?, @@ -176,6 +185,7 @@ private constructor( private var responseValidation: Boolean = false private var timeout: Timeout = Timeout.default() private var maxRetries: Int = 2 + private var logLevel: LogLevel = LogLevel.fromEnv() private var browserbaseApiKey: String? = null private var browserbaseProjectId: String? = null private var modelApiKey: String? = null @@ -194,6 +204,7 @@ private constructor( responseValidation = clientOptions.responseValidation timeout = clientOptions.timeout maxRetries = clientOptions.maxRetries + logLevel = clientOptions.logLevel browserbaseApiKey = clientOptions.browserbaseApiKey browserbaseProjectId = clientOptions.browserbaseProjectId modelApiKey = clientOptions.modelApiKey @@ -320,6 +331,15 @@ private constructor( */ fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries } + /** + * The level at which to log request and response information. + * + * [fromEnv] will set the level from environment variables. See [LogLevel.fromEnv]. + * + * Defaults to [LogLevel.fromEnv]. + */ + fun logLevel(logLevel: LogLevel) = apply { this.logLevel = logLevel } + /** Your [Browserbase API Key](https://www.browserbase.com/settings) */ fun browserbaseApiKey(browserbaseApiKey: String) = apply { this.browserbaseApiKey = browserbaseApiKey @@ -440,6 +460,7 @@ private constructor( * System properties take precedence over environment variables. */ fun fromEnv() = apply { + logLevel(LogLevel.fromEnv()) (System.getProperty("stagehand.baseUrl") ?: System.getenv("STAGEHAND_BASE_URL"))?.let { baseUrl(it) } @@ -532,7 +553,13 @@ private constructor( return ClientOptions( httpClient, RetryingHttpClient.builder() - .httpClient(httpClient) + .httpClient( + LoggingHttpClient.builder() + .httpClient(httpClient) + .clock(clock) + .level(logLevel) + .build() + ) .sleeper(sleeper) .clock(clock) .maxRetries(maxRetries) @@ -548,6 +575,7 @@ private constructor( responseValidation, timeout, maxRetries, + logLevel, browserbaseApiKey, browserbaseProjectId, modelApiKey, diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/LogLevel.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/LogLevel.kt new file mode 100644 index 0000000..f5a07a1 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/LogLevel.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.core + +/** The level at which to log request and response information. */ +enum class LogLevel { + /** No logging. */ + OFF, + /** Minimal request and response summary logs. No headers or bodies are logged. */ + INFO, + /** [INFO] logs plus details about request failures. */ + ERROR, + /** + * Full request and response logs. Sensitive headers are redacted, but sensitive data in request + * and response bodies may still be visible. + */ + DEBUG; + + /** Returns whether this level is at or higher than the given [level]. */ + fun shouldLog(level: LogLevel): Boolean = ordinal >= level.ordinal + + companion object { + + /** Returns a [LogLevel] based on the `STAGEHAND_LOG` environment variable. */ + fun fromEnv() = + when (System.getenv("STAGEHAND_LOG")?.lowercase()) { + "info" -> INFO + "error" -> ERROR + "debug" -> DEBUG + else -> OFF + } + } +} diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt index c24f648..ee3da60 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/Utils.kt @@ -5,6 +5,7 @@ package com.browserbase.api.core import com.browserbase.api.errors.StagehandInvalidDataException import java.util.Collections import java.util.SortedMap +import java.util.SortedSet import java.util.concurrent.CompletableFuture import java.util.concurrent.locks.Lock @@ -16,6 +17,11 @@ internal fun T?.getOrThrow(name: String): T = internal fun List.toImmutable(): List = if (isEmpty()) Collections.emptyList() else Collections.unmodifiableList(toList()) +@JvmSynthetic +internal fun > SortedSet.toImmutable(): SortedSet = + if (isEmpty()) Collections.emptySortedSet() + else Collections.unmodifiableSortedSet(toSortedSet(comparator() ?: Comparator.naturalOrder())) + @JvmSynthetic internal fun Map.toImmutable(): Map = if (isEmpty()) immutableEmptyMap() else Collections.unmodifiableMap(toMap()) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt new file mode 100644 index 0000000..9952373 --- /dev/null +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt @@ -0,0 +1,628 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.core.http + +import com.browserbase.api.core.LogLevel +import com.browserbase.api.core.RequestOptions +import com.browserbase.api.core.checkRequired +import com.browserbase.api.core.toImmutable +import java.io.ByteArrayOutputStream +import java.io.InputStream +import java.io.OutputStream +import java.nio.ByteBuffer +import java.nio.charset.CharacterCodingException +import java.nio.charset.Charset +import java.nio.charset.CharsetDecoder +import java.nio.charset.CodingErrorAction +import java.nio.charset.StandardCharsets +import java.time.Clock +import java.time.Duration +import java.time.OffsetDateTime +import java.util.SortedSet +import java.util.concurrent.CompletableFuture +import java.util.concurrent.CompletionException +import kotlin.time.toKotlinDuration + +/** A wrapper [HttpClient] around [httpClient] that logs request and response information. */ +class LoggingHttpClient +private constructor( + /** The underlying [HttpClient] for making requests. */ + @get:JvmName("httpClient") val httpClient: HttpClient, + /** + * Sensitive headers to redact from logs. + * + * Defaults to `Set.of("x-bb-api-key", "x-bb-project-id", "x-model-api-key")`. + */ + @get:JvmName("redactedHeaders") val redactedHeaders: SortedSet, + /** + * The clock to use for measuring request and response durations. + * + * This is primarily useful for using a fake clock in tests. + * + * Defaults to [Clock.systemUTC]. + */ + @get:JvmName("clock") val clock: Clock, + /** + * The log level to use. + * + * Pass [LogLevel.fromEnv] to read from environment variables. + */ + @get:JvmName("level") val level: LogLevel, +) : HttpClient { + + override fun execute(request: HttpRequest, requestOptions: RequestOptions): HttpResponse { + val loggingRequest = logRequest(request) + + val before = OffsetDateTime.now(clock) + val response = + try { + httpClient.execute(loggingRequest, requestOptions) + } catch (e: Throwable) { + logFailure(e, Duration.between(before, OffsetDateTime.now(clock))) + throw e + } + + val took = Duration.between(before, OffsetDateTime.now(clock)) + return logResponse(response, took) + } + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture { + val loggingRequest = logRequest(request) + + val before = OffsetDateTime.now(clock) + val future = + try { + httpClient.executeAsync(loggingRequest, requestOptions) + } catch (e: Throwable) { + logFailure(e, Duration.between(before, OffsetDateTime.now(clock))) + throw e + } + return future.handle { response, error -> + val took = Duration.between(before, OffsetDateTime.now(clock)) + if (error != null) { + logFailure(unwrapCompletionException(error), took) + throw error + } + logResponse(response, took) + } + } + + private fun logRequest(request: HttpRequest): HttpRequest { + if (!level.shouldLog(LogLevel.INFO)) { + return request + } + + System.err.println( + buildString { + append("--> ${request.method} ${request.url()}") + request.body?.let { + val length = it.contentLength() + append(if (length >= 0) " ($length-byte body)" else " (unknown-length body)") + } + } + ) + + if (!level.shouldLog(LogLevel.DEBUG)) { + return request + } + + logHeaders(request.headers) + + if (request.body == null) { + System.err.println("--> END ${request.method}") + System.err.println() + return request + } + + return request + .toBuilder() + .body(LoggingHttpRequestBody(request.method, request.body)) + .build() + } + + private fun logResponse(response: HttpResponse, took: Duration): HttpResponse { + if (!level.shouldLog(LogLevel.INFO)) { + return response + } + + val contentLength = response.headers().values("Content-Length").firstOrNull()?.toIntOrNull() + System.err.println( + "<-- ${response.statusCode()} (${ + buildString { + append(took.format()) + contentLength?.let { append(", $contentLength-byte body") } + } + })" + ) + + if (!level.shouldLog(LogLevel.DEBUG)) { + return response + } + + logHeaders(response.headers()) + return LoggingHttpResponse(response) + } + + private fun logFailure(error: Throwable, took: Duration) { + if (!level.shouldLog(LogLevel.ERROR)) { + return + } + + System.err.println( + buildString { + append("<-- !! ${error.javaClass.simpleName}") + error.message?.let { append(": $it") } + append(" (${took.format()})") + } + ) + } + + private fun unwrapCompletionException(error: Throwable): Throwable = + if (error is CompletionException && error.cause != null) error.cause!! else error + + private fun logHeaders(headers: Headers) = + headers.names().forEach { name -> + headers.values(name).forEach { value -> + System.err.println("$name: ${if (redactedHeaders.contains(name)) "██" else value}") + } + } + + override fun close() = httpClient.close() + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [LoggingHttpClient]. + * + * The following fields are required: + * ```java + * .httpClient() + * .level() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [LoggingHttpClient]. */ + class Builder internal constructor() { + + private var httpClient: HttpClient? = null + private var redactedHeaders: Set = + setOf("x-bb-api-key", "x-bb-project-id", "x-model-api-key") + private var clock: Clock = Clock.systemUTC() + private var level: LogLevel? = null + + @JvmSynthetic + internal fun from(loggingHttpClient: LoggingHttpClient) = apply { + httpClient = loggingHttpClient.httpClient + redactedHeaders = loggingHttpClient.redactedHeaders + clock = loggingHttpClient.clock + level = loggingHttpClient.level + } + + /** The underlying [HttpClient] for making requests. */ + fun httpClient(httpClient: HttpClient) = apply { this.httpClient = httpClient } + + /** + * Sensitive headers to redact from logs. + * + * Defaults to `Set.of("x-bb-api-key", "x-bb-project-id", "x-model-api-key")`. + */ + fun redactedHeaders(redactedHeaders: Set) = apply { + this.redactedHeaders = redactedHeaders + } + + /** + * The clock to use for measuring request and response durations. + * + * This is primarily useful for using a fake clock in tests. + * + * Defaults to [Clock.systemUTC]. + */ + fun clock(clock: Clock) = apply { this.clock = clock } + + /** + * The log level to use. + * + * Pass [LogLevel.fromEnv] to read from environment variables. + */ + fun level(level: LogLevel) = apply { this.level = level } + + /** + * Returns an immutable instance of [LoggingHttpClient]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .httpClient() + * .level() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): LoggingHttpClient = + LoggingHttpClient( + checkRequired("httpClient", httpClient), + redactedHeaders.toSortedSet(String.CASE_INSENSITIVE_ORDER).toImmutable(), + clock, + checkRequired("level", level), + ) + } +} + +/** + * An [HttpRequestBody] wrapper that delegates to [body] while also logging line by line as it's + * written. + * + * The logging occurs in a streaming manner with minimal buffering. + */ +private class LoggingHttpRequestBody( + private val method: HttpMethod, + private val body: HttpRequestBody, +) : HttpRequestBody { + + private val charset by lazy { parseCharset(body.contentType()) } + + override fun writeTo(outputStream: OutputStream) { + val loggingOutputStream = LoggingOutputStream(outputStream, charset) + body.writeTo(loggingOutputStream) + + loggingOutputStream.flush() + System.err.println("--> END $method (${loggingOutputStream.writeCount()}-byte body)") + System.err.println() + } + + override fun contentType(): String? = body.contentType() + + override fun contentLength(): Long = body.contentLength() + + override fun repeatable(): Boolean = body.repeatable() + + override fun close() = body.close() +} + +/** + * An [OutputStream] wrapper that delegates to [outputStream] while also logging bytes line by line + * as it's written to. + * + * The written content is assumed to be in the given [charset] and the logging occurs in a streaming + * manner with minimal buffering. + */ +private class LoggingOutputStream(private val outputStream: OutputStream, charset: Charset?) : + OutputStream() { + + private val buffer = LoggingBuffer(charset) + + fun writeCount() = buffer.writeCount() + + override fun write(b: Int) { + outputStream.write(b) + buffer.write(b) + } + + override fun write(b: ByteArray, off: Int, len: Int) { + outputStream.write(b, off, len) + for (i in off until off + len) { + buffer.write(b[i].toInt() and 0xFF) + } + } + + /** Prints any currently buffered content. */ + override fun flush() { + buffer.flush() + outputStream.flush() + } + + override fun close() = outputStream.close() +} + +/** + * An [HttpResponse] wrapper that delegates to [response] while also logging line-by-line as it's + * read. + * + * The logging occurs in a streaming manner with minimal buffering. + */ +private class LoggingHttpResponse(private val response: HttpResponse) : HttpResponse { + + private val loggingBody: Lazy = lazy { + LoggingInputStream( + response.body(), + parseCharset(response.headers().values("Content-Type").firstOrNull()), + ) + } + + override fun statusCode(): Int = response.statusCode() + + override fun headers(): Headers = response.headers() + + override fun body(): InputStream = loggingBody.value + + override fun close() { + if (loggingBody.isInitialized()) { + loggingBody.value.close() + } + response.close() + } +} + +/** + * An [InputStream] wrapper that delegates to [inputStream] while also logging bytes line by line as + * it's read. + * + * The contents of [inputStream] are assumed to be in the given [charset] and the logging occurs in + * a streaming manner with minimal buffering. + */ +private class LoggingInputStream(private val inputStream: InputStream, charset: Charset?) : + InputStream() { + + private var isDone = false + private val buffer = LoggingBuffer(charset) + + override fun read(): Int { + if (isDone) { + return -1 + } + + val b = inputStream.read() + + if (b == -1) { + markDone() + return b + } + + buffer.write(b) + return b + } + + override fun read(b: ByteArray, off: Int, len: Int): Int { + if (isDone) { + return -1 + } + + val bytesRead = inputStream.read(b, off, len) + + if (bytesRead == -1) { + markDone() + return bytesRead + } + + for (i in off until off + bytesRead) { + buffer.write(b[i].toInt() and 0xFF) + } + return bytesRead + } + + override fun close() { + if (!isDone) { + markDone(closedEarly = true) + } + inputStream.close() + } + + private fun markDone(closedEarly: Boolean = false) { + isDone = true + buffer.flush() + val suffix = if (closedEarly) ", closed early" else "" + System.err.println("<-- END HTTP (${buffer.writeCount()}-byte body$suffix)") + System.err.println() + } +} + +/** + * A byte buffer that prints line by line, using the given [charset], as bytes are written to it. + * + * When [charset] is `null`, the buffer performs an upfront check to detect binary content. If + * non-whitespace ISO control characters are found in the first [PROBABLY_UTF8_CODE_POINT_LIMIT] + * code points, body logging is suppressed entirely. + */ +private class LoggingBuffer(charset: Charset?) { + + private val charset = charset ?: StandardCharsets.UTF_8 + + private val decoder: CharsetDecoder = + this.charset + .newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT) + private var writeCount = 0 + private val buffer = ByteArrayOutputStream(128) + + /** + * Whether logging has been suppressed because the content doesn't appear to be readable text. + * + * This is only set when [charset] is `null` and the content fails the [isProbablyUtf8] check. + */ + private var suppressed = false + + /** + * Bytes accumulated for the [isProbablyUtf8] check before any lines are printed. + * + * Once the check passes (or [charset] is non-null), this is set to `null` and bytes flow + * directly to [buffer]. + */ + private var prefetchBuffer: ByteArrayOutputStream? = + if (charset != null) null else ByteArrayOutputStream(128) + + fun writeCount() = writeCount + + fun write(b: Int) { + if (writeCount == 0) { + // Print a newline before we start printing anything to separate the printed content + // from previous content. + System.err.println() + } + + writeCount++ + + if (suppressed) { + return + } + + val prefetch = prefetchBuffer + if (prefetch != null) { + prefetch.write(b) + // Continue accumulating until we have enough bytes to decide. + if (prefetch.size() < PROBABLY_UTF8_BYTE_LIMIT && b != '\n'.code) { + return + } + // We have enough bytes. Check if the content is probably UTF-8. + prefetchBuffer = null + val bytes = prefetch.toByteArray() + if (!isProbablyUtf8(bytes)) { + suppressed = true + System.err.println("(binary body omitted)") + return + } + // Content looks like UTF-8. Feed the accumulated bytes into the normal buffer. + for (byte in bytes) { + writeToBuffer(byte.toInt() and 0xFF) + } + return + } + + writeToBuffer(b) + } + + private fun writeToBuffer(b: Int) { + if (b == '\n'.code) { + flush() + return + } + + buffer.write(b) + } + + /** Prints any currently buffered content. */ + fun flush() { + if (suppressed) { + return + } + + // If we still have a prefetch buffer when flush is called (body was shorter than the + // limit), run the check now. + val prefetch = prefetchBuffer + if (prefetch != null) { + prefetchBuffer = null + val bytes = prefetch.toByteArray() + if (bytes.isEmpty()) { + return + } + if (!isProbablyUtf8(bytes)) { + suppressed = true + System.err.println("(binary body omitted)") + return + } + for (byte in bytes) { + writeToBuffer(byte.toInt() and 0xFF) + } + } + + if (buffer.size() == 0) { + return + } + + val line = + try { + decoder.decode(ByteBuffer.wrap(buffer.toByteArray())) + } catch (e: CharacterCodingException) { + "(omitted line is not valid $charset)" + } + buffer.reset() + System.err.println(line) + } +} + +/** The maximum number of code points to sample when checking if content is probably UTF-8. */ +private const val PROBABLY_UTF8_CODE_POINT_LIMIT = 64 + +/** + * The maximum number of bytes to accumulate before running the [isProbablyUtf8] check. UTF-8 code + * points are at most 4 bytes, so this accommodates [PROBABLY_UTF8_CODE_POINT_LIMIT] code points. + */ +private const val PROBABLY_UTF8_BYTE_LIMIT = PROBABLY_UTF8_CODE_POINT_LIMIT * 4 + +/** + * Returns `true` if the given [bytes] probably contain human-readable UTF-8 text. + * + * Decodes up to [PROBABLY_UTF8_CODE_POINT_LIMIT] code points and returns `false` if any + * non-whitespace ISO control characters are found, or if the bytes are not valid UTF-8. + */ +private fun isProbablyUtf8(bytes: ByteArray): Boolean { + try { + val decoder = + StandardCharsets.UTF_8.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT) + val charBuffer = decoder.decode(ByteBuffer.wrap(bytes)) + var codePointCount = 0 + var i = 0 + while (i < charBuffer.length && codePointCount < PROBABLY_UTF8_CODE_POINT_LIMIT) { + val codePoint = Character.codePointAt(charBuffer, i) + if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) { + return false + } + i += Character.charCount(codePoint) + codePointCount++ + } + return true + } catch (e: CharacterCodingException) { + return false + } +} + +/** Returns the [Charset] in the given [contentType] string, or `null` if unspecified. */ +private fun parseCharset(contentType: String?): Charset? = + contentType + ?.split(";") + ?.drop(1) + ?.map { it.trim() } + ?.firstOrNull { it.startsWith("charset=", ignoreCase = true) } + ?.substringAfter("=") + ?.trim() + ?.removeSurrounding("\"") + ?.let { runCatching { charset(it) }.getOrNull() } + +/** Formats the [Duration] into a string like "1m 40s 467ms". */ +private fun Duration.format(): String = + toKotlinDuration().toComponents { days, hours, minutes, seconds, nanoseconds -> + buildString { + val milliseconds = nanoseconds / 1_000_000 + if (days > 0) { + append("${days}d") + } + if (hours > 0) { + if (isNotEmpty()) { + append(" ") + } + append("${hours}h") + } + if (minutes > 0) { + if (isNotEmpty()) { + append(" ") + } + append("${minutes}m") + } + if (seconds > 0) { + if (isNotEmpty()) { + append(" ") + } + append("${seconds}s") + } + if (milliseconds > 0) { + if (isNotEmpty()) { + append(" ") + } + append("${milliseconds}ms") + } + + if (isEmpty()) { + append("0s") + } + } + } diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt new file mode 100644 index 0000000..b43c5d0 --- /dev/null +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt @@ -0,0 +1,999 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.browserbase.api.core.http + +import com.browserbase.api.core.LogLevel +import com.browserbase.api.core.RequestOptions +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.io.PrintStream +import java.nio.charset.StandardCharsets +import java.time.Clock +import java.time.Instant +import java.time.ZoneOffset +import java.util.concurrent.CompletableFuture +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.parallel.ResourceLock +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +@ResourceLock("stderr") +internal class LoggingHttpClientTest { + + private lateinit var originalErr: PrintStream + private lateinit var errContent: ByteArrayOutputStream + + @BeforeEach + fun beforeEach() { + originalErr = System.err + errContent = ByteArrayOutputStream() + System.setErr(PrintStream(errContent)) + } + + @AfterEach + fun afterEach() { + System.setErr(originalErr) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun offLevel_noOutput(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.OFF) + + val response = client.execute(simpleGetRequest(), async).apply { body().readBytes() } + + assertThat(response.statusCode()).isEqualTo(200) + assertThat(stderrOutput()).isEmpty() + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_logsGetRequest(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.INFO) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- 200 (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_logsPostRequestWithBodySize(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.INFO) + + client.execute(postRequestWithBody("""{"key":"value"}"""), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> POST https://api.example.com/v1/resources (15-byte body) + |<-- 200 (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_logsRequestWithUnknownLengthBody(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.INFO) + + client + .execute(postRequestWithBody("""{"key":"value"}""", contentLength = -1L), async) + .body() + .readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> POST https://api.example.com/v1/resources (unknown-length body) + |<-- 200 (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_logsResponseStatusAndDuration(async: Boolean) { + val clock = + clockFrom( + Instant.parse("1998-04-21T00:00:00Z"), + Instant.parse("1998-04-21T00:00:01.234Z"), + ) + val client = loggingClient(fakeHttpClient(statusCode = 201), LogLevel.INFO, clock) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- 201 (1s 234ms) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_logsResponseContentLength(async: Boolean) { + val headers = + Headers.builder().put("Content-Length", "42").put("Content-Type", "text/plain").build() + val client = loggingClient(fakeHttpClient(responseHeaders = headers), LogLevel.INFO) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- 200 (0s, 42-byte body) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_doesNotLogHeaders(async: Boolean) { + val headers = Headers.builder().put("X-Custom", "visible").build() + val client = loggingClient(fakeHttpClient(responseHeaders = headers), LogLevel.INFO) + + client + .execute( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("v1") + .putHeader("X-Request-Custom", "req-value") + .build(), + async, + ) + .body() + .readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1 + |<-- 200 (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsGetWithEndMarker(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.DEBUG) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |<-- END HTTP (0-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsRequestAndResponseHeaders(async: Boolean) { + val responseHeaders = + Headers.builder() + .put("X-Response-Id", "abc-123") + .put("Content-Type", "text/plain") + .build() + val client = + loggingClient(fakeHttpClient(responseHeaders = responseHeaders), LogLevel.DEBUG) + + client + .execute( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("test") + .putHeader("X-Custom", "my-value") + .build(), + async, + ) + .body() + .readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/test + |X-Custom: my-value + |--> END GET + | + |<-- 200 (0s) + |Content-Type: text/plain + |X-Response-Id: abc-123 + |<-- END HTTP (0-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_redactsSensitiveHeaders(async: Boolean) { + val client = + loggingClient( + fakeHttpClient(), + LogLevel.DEBUG, + redactedHeaders = setOf("Authorization", "X-Secret"), + ) + + client + .execute( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("test") + .putHeader("Authorization", "Bearer token-123") + .putHeader("X-Secret", "secret-value") + .putHeader("X-Public", "public-value") + .build(), + async, + ) + .body() + .readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/test + |Authorization: ██ + |X-Public: public-value + |X-Secret: ██ + |--> END GET + | + |<-- 200 (0s) + |<-- END HTTP (0-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_redactsHeadersCaseInsensitively(async: Boolean) { + val client = + loggingClient( + fakeHttpClient(), + LogLevel.DEBUG, + redactedHeaders = setOf("Authorization"), + ) + + client + .execute( + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("test") + .putHeader("authorization", "Bearer secret") + .build(), + async, + ) + .body() + .readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/test + |authorization: ██ + |--> END GET + | + |<-- 200 (0s) + |<-- END HTTP (0-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsRequestBody(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.DEBUG) + val body = """{"name":"test","value":42}""" + + client.execute(postRequestWithBody(body), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> POST https://api.example.com/v1/resources (26-byte body) + | + |{"name":"test","value":42} + |--> END POST (26-byte body) + | + |<-- 200 (0s) + |<-- END HTTP (0-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsResponseBody(async: Boolean) { + val responseBody = """{"id":1,"status":"ok"}""" + val headers = Headers.builder().put("Content-Type", "application/json").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = responseBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + val response = client.execute(simpleGetRequest(), async) + val body = response.body().readBytes().toString(StandardCharsets.UTF_8) + + assertThat(body).isEqualTo(responseBody) + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: application/json + | + |{"id":1,"status":"ok"} + |<-- END HTTP (22-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsBinaryResponseBodyAsOmitted(async: Boolean) { + val binaryBody = ByteArray(256) { it.toByte() } + val client = loggingClient(fakeHttpClient(responseBody = binaryBody), LogLevel.DEBUG) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + | + |(binary body omitted) + |<-- END HTTP (256-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsMultilineResponseBody(async: Boolean) { + val multilineBody = "line1\nline2\nline3" + val headers = Headers.builder().put("Content-Type", "text/plain; charset=utf-8").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = multilineBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: text/plain; charset=utf-8 + | + |line1 + |line2 + |line3 + |<-- END HTTP (17-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsResponseBodyWithExplicitCharset(async: Boolean) { + val responseBody = "héllo wörld" + val headers = Headers.builder().put("Content-Type", "text/plain; charset=utf-8").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = responseBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: text/plain; charset=utf-8 + | + |héllo wörld + |<-- END HTTP (13-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsResponseBodyWithNoContentType(async: Boolean) { + val responseBody = "plain text body" + val client = + loggingClient( + fakeHttpClient(responseBody = responseBody.toByteArray(StandardCharsets.UTF_8)), + LogLevel.DEBUG, + ) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + | + |plain text body + |<-- END HTTP (15-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsEmptyResponseBody(async: Boolean) { + val client = loggingClient(fakeHttpClient(), LogLevel.DEBUG) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |<-- END HTTP (0-byte body) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsEndHttpMarkerOnEarlyClose(async: Boolean) { + val responseBody = """{"id":1,"status":"ok"}""" + val headers = Headers.builder().put("Content-Type", "application/json").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = responseBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + val body = client.execute(simpleGetRequest(), async).body() + body.read(ByteArray(5)) + body.close() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: application/json + | + |{"id" + |<-- END HTTP (5-byte body, closed early) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsEndHttpMarkerOnCloseWithoutReading(async: Boolean) { + val responseBody = """{"id":1,"status":"ok"}""" + val headers = Headers.builder().put("Content-Type", "application/json").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = responseBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + client.execute(simpleGetRequest(), async).body().close() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: application/json + |<-- END HTTP (0-byte body, closed early) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsEndHttpMarkerWhenResponseClosedAfterPartialRead(async: Boolean) { + val responseBody = """{"id":1,"status":"ok"}""" + val headers = Headers.builder().put("Content-Type", "application/json").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = responseBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + val response = client.execute(simpleGetRequest(), async) + response.body().read(ByteArray(5)) + response.close() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: application/json + | + |{"id" + |<-- END HTTP (5-byte body, closed early) + | + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_doesNotLogEndHttpMarkerWhenResponseClosedWithoutBodyAccess(async: Boolean) { + val responseBody = """{"id":1,"status":"ok"}""" + val headers = Headers.builder().put("Content-Type", "application/json").build() + val client = + loggingClient( + fakeHttpClient( + responseHeaders = headers, + responseBody = responseBody.toByteArray(StandardCharsets.UTF_8), + ), + LogLevel.DEBUG, + ) + + client.execute(simpleGetRequest(), async).close() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- 200 (0s) + |Content-Type: application/json + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun errorLevel_logsRequestFailure(async: Boolean) { + val clock = + clockFrom( + Instant.parse("1998-04-21T00:00:00Z"), + Instant.parse("1998-04-21T00:00:01.234Z"), + ) + val client = + loggingClient( + failingHttpClient(IOException("Connection refused")), + LogLevel.ERROR, + clock, + ) + + assertThatThrownBy { client.execute(simpleGetRequest(), async) } + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- !! IOException: Connection refused (1s 234ms) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun infoLevel_doesNotLogRequestFailure(async: Boolean) { + val client = + loggingClient(failingHttpClient(IOException("Connection refused")), LogLevel.INFO) + + assertThatThrownBy { client.execute(simpleGetRequest(), async) } + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun debugLevel_logsRequestFailureAfterHeaders(async: Boolean) { + val client = + loggingClient(failingHttpClient(IOException("Connection refused")), LogLevel.DEBUG) + + assertThatThrownBy { client.execute(simpleGetRequest(), async) } + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |--> END GET + | + |<-- !! IOException: Connection refused (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun errorLevel_logsRequestFailureWithoutMessage(async: Boolean) { + val client = loggingClient(failingHttpClient(IOException()), LogLevel.ERROR) + + assertThatThrownBy { client.execute(simpleGetRequest(), async) } + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- !! IOException (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun offLevel_doesNotLogRequestFailure(async: Boolean) { + val client = + loggingClient(failingHttpClient(IOException("Connection refused")), LogLevel.OFF) + + assertThatThrownBy { client.execute(simpleGetRequest(), async) } + + assertThat(stderrOutput()).isEmpty() + } + + @Test + fun errorLevel_logsExecuteAsyncSynchronousThrow() { + val error = IOException("Connection refused") + val client = + loggingClient( + object : HttpClient { + override fun execute( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse = throw UnsupportedOperationException() + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture = throw error + + override fun close() {} + }, + LogLevel.ERROR, + ) + + assertThatThrownBy { client.execute(simpleGetRequest(), async = true) }.isSameAs(error) + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- !! IOException: Connection refused (0s) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun durationFormat_seconds(async: Boolean) { + val clock = + clockFrom( + Instant.parse("1998-04-21T00:00:00Z"), + Instant.parse("1998-04-21T00:00:02.500Z"), + ) + val client = loggingClient(fakeHttpClient(), LogLevel.INFO, clock) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- 200 (2s 500ms) + |""" + .trimMargin() + ) + } + + @ParameterizedTest + @ValueSource(booleans = [false, true]) + fun durationFormat_minutesAndSeconds(async: Boolean) { + val clock = + clockFrom( + Instant.parse("1998-04-21T00:00:00Z"), + Instant.parse("1998-04-21T00:01:40.467Z"), + ) + val client = loggingClient(fakeHttpClient(), LogLevel.INFO, clock) + + client.execute(simpleGetRequest(), async).body().readBytes() + + assertThat(stderrOutput()) + .isEqualTo( + """ + |--> GET https://api.example.com/v1/resources + |<-- 200 (1m 40s 467ms) + |""" + .trimMargin() + ) + } + + @Test + fun builder_toBuilder_roundtrips() { + val delegate = fakeHttpClient() + val clock = Clock.fixed(Instant.parse("1998-04-21T00:00:00Z"), ZoneOffset.UTC) + val client = + LoggingHttpClient.builder() + .httpClient(delegate) + .level(LogLevel.DEBUG) + .redactedHeaders(setOf("X-Secret")) + .clock(clock) + .build() + + val rebuilt = client.toBuilder().build() + + assertThat(rebuilt.httpClient).isSameAs(delegate) + assertThat(rebuilt.level).isEqualTo(LogLevel.DEBUG) + assertThat(rebuilt.redactedHeaders).containsExactly("X-Secret") + assertThat(rebuilt.clock).isEqualTo(clock) + } + + @Test + fun close_delegatesToUnderlyingClient() { + var closed = false + val delegate = + object : HttpClient { + override fun execute( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse = throw UnsupportedOperationException() + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture = throw UnsupportedOperationException() + + override fun close() { + closed = true + } + } + val client = loggingClient(delegate, LogLevel.OFF) + + client.close() + + assertThat(closed).isTrue() + } + + private fun stderrOutput(): String = errContent.toString("UTF-8") + + private fun loggingClient( + httpClient: HttpClient, + level: LogLevel, + clock: Clock = clockFrom(Instant.parse("1998-04-21T00:00:00Z")), + redactedHeaders: Set = setOf("x-bb-api-key", "x-bb-project-id", "x-model-api-key"), + ): LoggingHttpClient = + LoggingHttpClient.builder() + .httpClient(httpClient) + .level(level) + .clock(clock) + .redactedHeaders(redactedHeaders) + .build() + + private fun simpleGetRequest(): HttpRequest = + HttpRequest.builder() + .method(HttpMethod.GET) + .baseUrl("https://api.example.com") + .addPathSegment("v1") + .addPathSegment("resources") + .build() + + private fun postRequestWithBody( + body: String, + contentType: String = "application/json", + contentLength: Long? = null, + ): HttpRequest = + HttpRequest.builder() + .method(HttpMethod.POST) + .baseUrl("https://api.example.com") + .addPathSegment("v1") + .addPathSegment("resources") + .body( + object : HttpRequestBody { + private val bytes = body.toByteArray(StandardCharsets.UTF_8) + + override fun writeTo(outputStream: OutputStream) { + outputStream.write(bytes) + } + + override fun contentType(): String = contentType + + override fun contentLength(): Long = contentLength ?: bytes.size.toLong() + + override fun repeatable(): Boolean = true + + override fun close() {} + } + ) + .build() + + private fun fakeHttpClient( + statusCode: Int = 200, + responseHeaders: Headers = Headers.builder().build(), + responseBody: ByteArray = ByteArray(0), + ): HttpClient = + object : HttpClient { + override fun execute( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse { + // Consume the request body if present to trigger logging. + request.body?.let { + val out = ByteArrayOutputStream() + it.writeTo(out) + } + return fakeResponse(statusCode, responseHeaders, responseBody) + } + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture = + CompletableFuture.completedFuture(execute(request, requestOptions)) + + override fun close() {} + } + + private fun failingHttpClient(error: Throwable): HttpClient = + object : HttpClient { + override fun execute( + request: HttpRequest, + requestOptions: RequestOptions, + ): HttpResponse { + request.body?.let { + val out = ByteArrayOutputStream() + it.writeTo(out) + } + throw error + } + + override fun executeAsync( + request: HttpRequest, + requestOptions: RequestOptions, + ): CompletableFuture { + val future = CompletableFuture() + future.completeExceptionally(error) + return future + } + + override fun close() {} + } + + private fun fakeResponse(statusCode: Int, headers: Headers, body: ByteArray): HttpResponse = + object : HttpResponse { + override fun statusCode(): Int = statusCode + + override fun headers(): Headers = headers + + override fun body(): InputStream = ByteArrayInputStream(body) + + override fun close() {} + } + + private fun clockFrom(vararg instants: Instant): Clock = + object : Clock() { + private var index = 0 + + override fun getZone() = ZoneOffset.UTC + + override fun withZone(zone: java.time.ZoneId?) = this + + override fun instant(): Instant { + val instant = instants[index % instants.size] + index++ + return instant + } + } + + private fun HttpClient.execute(request: HttpRequest, async: Boolean): HttpResponse = + if (async) executeAsync(request).get() else execute(request) +} From 711359a6709f06cd547000456d6525f30b819821 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 16:21:01 +0000 Subject: [PATCH 159/164] chore(internal): version bump --- .release-please-manifest.json | 2 +- README.md | 10 +++++----- build.gradle.kts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 911c623..d11c8fc 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.19.3" + ".": "3.20.0" } \ No newline at end of file diff --git a/README.md b/README.md index ab5d48e..e2281bf 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ -[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/3.19.3) -[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/3.19.3/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.19.3) +[![Maven Central](https://img.shields.io/maven-central/v/com.browserbase.api/stagehand-java)](https://central.sonatype.com/artifact/com.browserbase.api/stagehand-java/3.20.0) +[![javadoc](https://javadoc.io/badge2/com.browserbase.api/stagehand-java/3.20.0/javadoc.svg)](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.20.0) @@ -15,7 +15,7 @@ It is generated with [Stainless](https://www.stainless.com/). -The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.19.3). +The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.browserbase.api/stagehand-java/3.20.0). @@ -26,7 +26,7 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta ### Gradle ```kotlin -implementation("com.browserbase.api:stagehand-java:3.19.3") +implementation("com.browserbase.api:stagehand-java:3.20.0") ``` ### Maven @@ -35,7 +35,7 @@ implementation("com.browserbase.api:stagehand-java:3.19.3") com.browserbase.api stagehand-java - 3.19.3 + 3.20.0 ``` diff --git a/build.gradle.kts b/build.gradle.kts index effad83..4602d16 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ repositories { allprojects { group = "com.browserbase.api" - version = "3.19.3" // x-release-please-version + version = "3.20.0" // x-release-please-version } subprojects { From e064a07b9c9ac89772c06596056fd5707a7f2e8d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 17:46:11 +0000 Subject: [PATCH 160/164] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 391cde3..57aa7a5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-6f6bfb81d092f30a5e2005328c97d61b9ea36132bb19e9e79e55294b9534ce20.yml -openapi_spec_hash: f3fc1e3688a38dc2c28f7178f7d534e5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-e629569417ad17cad5c73180109b4c3ae778f38063fc72146fa82f82de145911.yml +openapi_spec_hash: 42e4eedbc0fcc772bb271191a067bce1 config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 From 403de4c606e81587f3a7aef6c24b05449d888a06 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 18:23:01 +0000 Subject: [PATCH 161/164] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 57aa7a5..094ac49 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-e629569417ad17cad5c73180109b4c3ae778f38063fc72146fa82f82de145911.yml -openapi_spec_hash: 42e4eedbc0fcc772bb271191a067bce1 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-49b40c7425adba9e67fc102838c5216c45ca1f7ef4c10823c5665fd413538504.yml +openapi_spec_hash: 6880dc029df2e88dfe8943c0dec5a3a5 config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 From 8e6c45f6febcf94d67b7fa8958d0e29ca4cf85a0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 18:25:46 +0000 Subject: [PATCH 162/164] feat: [feat]: add `ignoreSelectors` to `observe()` --- .stats.yml | 4 +- .../models/sessions/SessionObserveParams.kt | 73 +++++++++++++++++-- .../sessions/SessionObserveParamsTest.kt | 4 + .../services/async/SessionServiceAsyncTest.kt | 2 + .../services/blocking/SessionServiceTest.kt | 2 + 5 files changed, 78 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index 094ac49..0339c57 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-49b40c7425adba9e67fc102838c5216c45ca1f7ef4c10823c5665fd413538504.yml -openapi_spec_hash: 6880dc029df2e88dfe8943c0dec5a3a5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-eae8400fade7b2c8329c4148f56de92e147c34c0feecb420c015aab6544a9acc.yml +openapi_spec_hash: 0a9eff1ac1d464e89cbd9db64709b08a config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt index 8331e8b..dd8ffaa 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/models/sessions/SessionObserveParams.kt @@ -11,6 +11,7 @@ import com.browserbase.api.core.JsonMissing import com.browserbase.api.core.JsonValue import com.browserbase.api.core.Params import com.browserbase.api.core.allMaxBy +import com.browserbase.api.core.checkKnown import com.browserbase.api.core.getOrThrow import com.browserbase.api.core.http.Headers import com.browserbase.api.core.http.QueryParams @@ -573,6 +574,7 @@ private constructor( class Options @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( + private val ignoreSelectors: JsonField>, private val model: JsonField, private val selector: JsonField, private val timeout: JsonField, @@ -582,6 +584,9 @@ private constructor( @JsonCreator private constructor( + @JsonProperty("ignoreSelectors") + @ExcludeMissing + ignoreSelectors: JsonField> = JsonMissing.of(), @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("selector") @ExcludeMissing @@ -590,7 +595,16 @@ private constructor( @JsonProperty("variables") @ExcludeMissing variables: JsonField = JsonMissing.of(), - ) : this(model, selector, timeout, variables, mutableMapOf()) + ) : this(ignoreSelectors, model, selector, timeout, variables, mutableMapOf()) + + /** + * Selectors for elements and subtrees that should be excluded from observation + * + * @throws StagehandInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun ignoreSelectors(): Optional> = + ignoreSelectors.getOptional("ignoreSelectors") /** * Model configuration object or model name string (e.g., 'openai/gpt-5-nano') @@ -626,6 +640,16 @@ private constructor( */ fun variables(): Optional = variables.getOptional("variables") + /** + * Returns the raw JSON value of [ignoreSelectors]. + * + * Unlike [ignoreSelectors], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("ignoreSelectors") + @ExcludeMissing + fun _ignoreSelectors(): JsonField> = ignoreSelectors + /** * Returns the raw JSON value of [model]. * @@ -677,6 +701,7 @@ private constructor( /** A builder for [Options]. */ class Builder internal constructor() { + private var ignoreSelectors: JsonField>? = null private var model: JsonField = JsonMissing.of() private var selector: JsonField = JsonMissing.of() private var timeout: JsonField = JsonMissing.of() @@ -685,6 +710,7 @@ private constructor( @JvmSynthetic internal fun from(options: Options) = apply { + ignoreSelectors = options.ignoreSelectors.map { it.toMutableList() } model = options.model selector = options.selector timeout = options.timeout @@ -692,6 +718,33 @@ private constructor( additionalProperties = options.additionalProperties.toMutableMap() } + /** Selectors for elements and subtrees that should be excluded from observation */ + fun ignoreSelectors(ignoreSelectors: List) = + ignoreSelectors(JsonField.of(ignoreSelectors)) + + /** + * Sets [Builder.ignoreSelectors] to an arbitrary JSON value. + * + * You should usually call [Builder.ignoreSelectors] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun ignoreSelectors(ignoreSelectors: JsonField>) = apply { + this.ignoreSelectors = ignoreSelectors.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [ignoreSelectors]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addIgnoreSelector(ignoreSelector: String) = apply { + ignoreSelectors = + (ignoreSelectors ?: JsonField.of(mutableListOf())).also { + checkKnown("ignoreSelectors", it).add(ignoreSelector) + } + } + /** Model configuration object or model name string (e.g., 'openai/gpt-5-nano') */ fun model(model: Model) = model(JsonField.of(model)) @@ -775,7 +828,14 @@ private constructor( * Further updates to this [Builder] will not mutate the returned instance. */ fun build(): Options = - Options(model, selector, timeout, variables, additionalProperties.toMutableMap()) + Options( + (ignoreSelectors ?: JsonMissing.of()).map { it.toImmutable() }, + model, + selector, + timeout, + variables, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -794,6 +854,7 @@ private constructor( return@apply } + ignoreSelectors() model().ifPresent { it.validate() } selector() timeout() @@ -817,7 +878,8 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (model.asKnown().getOrNull()?.validity() ?: 0) + + (ignoreSelectors.asKnown().getOrNull()?.size ?: 0) + + (model.asKnown().getOrNull()?.validity() ?: 0) + (if (selector.asKnown().isPresent) 1 else 0) + (if (timeout.asKnown().isPresent) 1 else 0) + (variables.asKnown().getOrNull()?.validity() ?: 0) @@ -1157,6 +1219,7 @@ private constructor( } return other is Options && + ignoreSelectors == other.ignoreSelectors && model == other.model && selector == other.selector && timeout == other.timeout && @@ -1165,13 +1228,13 @@ private constructor( } private val hashCode: Int by lazy { - Objects.hash(model, selector, timeout, variables, additionalProperties) + Objects.hash(ignoreSelectors, model, selector, timeout, variables, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "Options{model=$model, selector=$selector, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" + "Options{ignoreSelectors=$ignoreSelectors, model=$model, selector=$selector, timeout=$timeout, variables=$variables, additionalProperties=$additionalProperties}" } /** Whether to stream the response via SSE */ diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt index 08f0c13..df6c3f7 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/models/sessions/SessionObserveParamsTest.kt @@ -18,6 +18,7 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -72,6 +73,7 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -130,6 +132,7 @@ internal class SessionObserveParamsTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -170,6 +173,7 @@ internal class SessionObserveParamsTest { assertThat(body.options()) .contains( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt index 8d708e4..369528c 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/async/SessionServiceAsyncTest.kt @@ -461,6 +461,7 @@ internal class SessionServiceAsyncTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -519,6 +520,7 @@ internal class SessionServiceAsyncTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt index 7ede1f2..2cea0fd 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/services/blocking/SessionServiceTest.kt @@ -456,6 +456,7 @@ internal class SessionServiceTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") @@ -513,6 +514,7 @@ internal class SessionServiceTest { .instruction("Find all clickable navigation links") .options( SessionObserveParams.Options.builder() + .ignoreSelectors(listOf("nav", ".cookie-banner", "#sidebar-ads")) .model( ModelConfig.builder() .modelName("openai/gpt-5.4-mini") From 65a4e759b66efc8336e123e98708b90e7c3f9782 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 02:01:14 +0000 Subject: [PATCH 163/164] chore: redact api-key headers in debug logs --- .../api/core/http/LoggingHttpClient.kt | 17 ++++++++++++++--- .../api/core/http/LoggingHttpClientTest.kt | 12 +++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt index 9952373..564bbfc 100644 --- a/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt +++ b/stagehand-java-core/src/main/kotlin/com/browserbase/api/core/http/LoggingHttpClient.kt @@ -31,7 +31,8 @@ private constructor( /** * Sensitive headers to redact from logs. * - * Defaults to `Set.of("x-bb-api-key", "x-bb-project-id", "x-model-api-key")`. + * Defaults to `Set.of("authorization", "api-key", "x-api-key", "cookie", "set-cookie", + * "x-bb-api-key", "x-bb-project-id", "x-model-api-key")`. */ @get:JvmName("redactedHeaders") val redactedHeaders: SortedSet, /** @@ -193,7 +194,16 @@ private constructor( private var httpClient: HttpClient? = null private var redactedHeaders: Set = - setOf("x-bb-api-key", "x-bb-project-id", "x-model-api-key") + setOf( + "authorization", + "api-key", + "x-api-key", + "cookie", + "set-cookie", + "x-bb-api-key", + "x-bb-project-id", + "x-model-api-key", + ) private var clock: Clock = Clock.systemUTC() private var level: LogLevel? = null @@ -211,7 +221,8 @@ private constructor( /** * Sensitive headers to redact from logs. * - * Defaults to `Set.of("x-bb-api-key", "x-bb-project-id", "x-model-api-key")`. + * Defaults to `Set.of("authorization", "api-key", "x-api-key", "cookie", "set-cookie", + * "x-bb-api-key", "x-bb-project-id", "x-model-api-key")`. */ fun redactedHeaders(redactedHeaders: Set) = apply { this.redactedHeaders = redactedHeaders diff --git a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt index b43c5d0..a35c99d 100644 --- a/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt +++ b/stagehand-java-core/src/test/kotlin/com/browserbase/api/core/http/LoggingHttpClientTest.kt @@ -870,7 +870,17 @@ internal class LoggingHttpClientTest { httpClient: HttpClient, level: LogLevel, clock: Clock = clockFrom(Instant.parse("1998-04-21T00:00:00Z")), - redactedHeaders: Set = setOf("x-bb-api-key", "x-bb-project-id", "x-model-api-key"), + redactedHeaders: Set = + setOf( + "authorization", + "api-key", + "x-api-key", + "cookie", + "set-cookie", + "x-bb-api-key", + "x-bb-project-id", + "x-model-api-key", + ), ): LoggingHttpClient = LoggingHttpClient.builder() .httpClient(httpClient) From 596382c06859bfa22a6bfbe1f756e4bfd28537e0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 02:00:40 +0000 Subject: [PATCH 164/164] ci: pin GitHub Actions to commit SHAs Pin all GitHub Actions referenced in generated workflows (both first-party `actions/*` and third-party) to immutable commit SHAs. Updating pinned actions is now a deliberate codegen-side bump rather than implicit on every workflow run. --- .github/workflows/ci.yml | 20 ++++++++++---------- .github/workflows/publish-sonatype.yml | 6 +++--- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8d4c5a..b11acac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,10 +22,10 @@ jobs: 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@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: | @@ -34,7 +34,7 @@ jobs: cache: gradle - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Run lints run: ./scripts/lint @@ -49,10 +49,10 @@ jobs: 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@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: | @@ -61,7 +61,7 @@ jobs: cache: gradle - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3 - name: Build SDK run: ./scripts/build @@ -71,7 +71,7 @@ jobs: github.repository == 'stainless-sdks/stagehand-java' && !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -91,10 +91,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/stagehand-java' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: | @@ -103,7 +103,7 @@ jobs: cache: gradle - name: Set up Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@a8f75513eafdebd8141bd1cd4e30fcd194af8dfa # v2.12.0 - name: Run tests run: ./scripts/test diff --git a/.github/workflows/publish-sonatype.yml b/.github/workflows/publish-sonatype.yml index e0e380c..ebab6f0 100644 --- a/.github/workflows/publish-sonatype.yml +++ b/.github/workflows/publish-sonatype.yml @@ -14,10 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: temurin java-version: | @@ -26,7 +26,7 @@ jobs: cache: gradle - name: Set up Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@a8f75513eafdebd8141bd1cd4e30fcd194af8dfa # v2.12.0 - name: Publish to Sonatype run: |- diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index e71595c..4fcd85e 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'browserbase/stagehand-java' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: |